chart.html 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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 type="text/javascript">
  20. const testData = [
  21. {
  22. name: '开埠通商',
  23. desc: '开埠通商的描述开埠通商的描述开埠通商的描述开埠通商的描述开埠通商的描述开埠通商的描述开埠通商的描述',
  24. corps: [
  25. {
  26. name: '李鸿章',
  27. brand: '创办江南制造局、上海机器织布局。',
  28. desc: '',
  29. story: '江南制造总局:中国民族工业从此起步;上海机器织布局:开创中国近代纺织业之先河。',
  30. importance: 30,
  31. id: '1'
  32. },
  33. {
  34. name: '徐寿',
  35. brand: '上海江南制造总局',
  36. desc: '清代著名科学家,上海江南制造总局襄办。',
  37. story: '',
  38. importance: 40,
  39. id: '2'
  40. },
  41. {
  42. name: '刘永康',
  43. brand: '正泰橡皮物品制造厂',
  44. desc: '创办正泰橡皮物品制造厂,首创“回力”商标。',
  45. story: '',
  46. importance: 50,
  47. id: '3'
  48. },
  49. ]
  50. },
  51. {
  52. name: '曲折发展',
  53. desc: '曲折发展的描述曲折发展的描述曲折发展的描述曲折发展的描述曲折发展的描述曲折发展的描述曲折发展的描述曲折发展的描述',
  54. corps: [
  55. {
  56. name: '黄佐卿',
  57. brand: '裕晋纱厂',
  58. desc: '1895年投资的裕晋纱厂在上海杨树浦路落成并开工投产',
  59. story: '',
  60. importance: 30,
  61. id: '1'
  62. },
  63. {
  64. name: '孙多森、孙多鑫',
  65. brand: '阜丰面粉厂',
  66. desc: '1900年集资创办上海第一家民族机器面粉厂“阜丰面粉厂”',
  67. story: '孙氏通、孚、丰集团:官办企业转化为民族资本企业的典型。',
  68. importance: 30,
  69. id: '2'
  70. },
  71. {
  72. name: '严裕棠',
  73. brand: '大隆机器厂',
  74. desc: '1902年开办的大隆机器厂',
  75. story: '',
  76. importance: 30,
  77. id: '3'
  78. },
  79. {
  80. name: '张士德、刘致祥',
  81. brand: '中国精益眼镜公司',
  82. desc: '1911年集资开设中国精益眼镜公司',
  83. story: '',
  84. importance: 30,
  85. id: '4'
  86. },
  87. {
  88. name: '荣宗敬、荣德生',
  89. brand: '第一家面粉厂、申新纺织公司',
  90. desc: '第一家面粉厂,1915年,荣氏兄弟又创建申新纺织公司,人称“棉纱大王”。1919年至1921年,又发起和参与了上海华商面粉交易所、纱布交易所,成为上海民族工业的重要台柱之一。',
  91. story: '荣氏企业:上海民族工业的重要台柱之一。',
  92. importance: 30,
  93. id: '5'
  94. },
  95. ]
  96. },
  97. ]
  98. function randomColor() {
  99. return '#' + Math.floor(
  100. (
  101. Math.random() * (1 - 0.3) + 0.3
  102. ) * 0xffffff
  103. ).toString(16)
  104. }
  105. const dataForRender = {}
  106. let myChart = null
  107. var dom = document.getElementById('container');
  108. myChart = echarts.init(dom, null, {
  109. renderer: 'canvas',
  110. useDirtyRect: false
  111. });
  112. function showChart(timeIdx) {
  113. myChart.clear()
  114. dataForRender.nodes = [
  115. {
  116. name: testData[timeIdx].name,
  117. id: '0',
  118. symbolSize: 100,
  119. itemStyle: {
  120. color: randomColor()
  121. },
  122. },
  123. ]
  124. dataForRender.edges = []
  125. for (const iterator of testData[timeIdx].corps) {
  126. const newNode = {
  127. name: iterator.brand,
  128. id: iterator.id,
  129. symbolSize: iterator.importance,
  130. itemStyle: {
  131. color: randomColor()
  132. }
  133. }
  134. dataForRender.nodes.push(newNode)
  135. }
  136. // 除了代表时代的那个节点,其他节点的尺寸归一化到[10, 70]
  137. let vMax = Number.NEGATIVE_INFINITY
  138. let vMin = Number.POSITIVE_INFINITY
  139. const vMaxNew = 50
  140. const vMinNew = 30
  141. for (let index = 1; index < dataForRender.nodes.length; index++) {
  142. const size = dataForRender.nodes[index].symbolSize
  143. if (size > vMax) {
  144. vMax = size
  145. }
  146. if (size < vMin) {
  147. vMin = size
  148. }
  149. }
  150. let scale = null
  151. if (vMax === vMin) {
  152. scale = 1
  153. for (const iterator of dataForRender.nodes.slice(1)) {
  154. iterator.symbolSize = vMinNew + (vMaxNew - vMinNew) / 2
  155. }
  156. } else {
  157. scale = (vMaxNew - vMinNew) / (vMax - vMin)
  158. for (const iterator of dataForRender.nodes.slice(1)) {
  159. iterator.symbolSize = vMinNew + (iterator.symbolSize - vMin) * scale
  160. }
  161. }
  162. // console.log(dataForRender.nodes);
  163. for (let i = 0; i < dataForRender.nodes.length; i++) {
  164. for (let j = i + 1; j < dataForRender.nodes.length; j++) {
  165. const hasCenterNode = (i === 0 || j === 0)
  166. const newEdge = {
  167. source: dataForRender.nodes[i].id,
  168. target: dataForRender.nodes[j].id,
  169. value: dataForRender.nodes[i].symbolSize * dataForRender.nodes[j].symbolSize * (hasCenterNode ? 10 : 1), // 值越大,连接的两个节点间斥力越小。
  170. }
  171. dataForRender.edges.push(newEdge)
  172. }
  173. }
  174. // console.log(dataForRender);
  175. myChart.setOption({
  176. animationDurationUpdate: 1500,
  177. animationEasingUpdate: 'quinticInOut',
  178. series: [
  179. {
  180. type: 'graph',
  181. layout: 'force',
  182. draggable: false,
  183. // 力引导布局是模拟弹簧电荷模型在每两个节点之间添加一个斥力,每条边的两个节点之间添加一个引力
  184. force: {
  185. initLayout: 'circular', // 进行力引导布局前的初始化布局,初始化布局会影响到力引导的效果。默认不进行任何布局,使用节点中提供的 x, y 作为节点的位置。如果不存在的话会随机生成一个位置。也可以选择使用环形布局 'circular'。
  186. repulsion: 100, // 节点之间的斥力因子。傻逼文档把edgeLength当数组用的用法写到这上边了。
  187. gravity: 0.1, // 节点受到的向中心的引力因子。该值越大节点越往中心点靠拢。
  188. edgeLength: [50, 400], // 把各个边的两个节点之间的距离归一化到这个范围内。与repulsion共同作用。
  189. layoutAnimation: true,
  190. friction: 0.1, // 这个参数能减缓节点的移动速度。取值范围 0 到 1。但是仍然是个试验性的参数,参见 #11024。
  191. },
  192. data: dataForRender.nodes,
  193. // 或者叫edges
  194. links: dataForRender.edges,
  195. selectedMode: 'single',
  196. select: {
  197. itemStyle: {
  198. shadowBlur: 50,
  199. shadowColor: 'rgba(255, 255, 125, 0.7)',
  200. },
  201. label: {
  202. position: 'right',
  203. show: true,
  204. }
  205. },
  206. // 高亮状态的图形样式
  207. emphasis: {
  208. scale: false,
  209. label: {
  210. position: 'right',
  211. show: true
  212. }
  213. },
  214. // 图表是否可以移动、缩放
  215. roam: true,
  216. lineStyle: {
  217. width: 0.5,
  218. curveness: 0.3,
  219. opacity: 0.7,
  220. }
  221. }
  222. ]
  223. }, true)
  224. setTimeout(() => {
  225. // 等myChart上注册了select回调后再执行
  226. // 一开始自动选中0号节点,也就是表示时代的那个
  227. myChart.dispatchAction({
  228. type: 'select',
  229. seriesIndex: 0,
  230. name: testData[timeIdx].name,
  231. })
  232. }, 0);
  233. }
  234. showChart(0)
  235. // 用户选中节点后,向父窗口post message
  236. function onSelect(params) {
  237. if (params.dataType === 'node') { // 用户选中节点触发的
  238. window.parent.postMessage(`node-selected: ${dataForRender.nodes[params.dataIndexInside].id}`, '*')
  239. } else if (params.type === 'select') { // 程序里调用dispatchAction触发的,且type为select
  240. console.log('iframe message: emitting...');
  241. window.parent.postMessage(`node-selected: 0`, '*')
  242. }
  243. }
  244. myChart.on('select', onSelect)
  245. window.addEventListener('resize', myChart.resize);
  246. // 切换时代
  247. window.changeTime = function (idx) {
  248. if (Number.isInteger(idx) && idx >= 0) {
  249. showChart(idx)
  250. } else {
  251. console.error('[page using echart] changeTime: invalid param!', idx);
  252. }
  253. }
  254. </script>
  255. </body>
  256. </html>