index.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import React, { PureComponent } from 'react';
  2. import classNames from 'classnames';
  3. import G2 from 'g2';
  4. import Cloud from 'g-cloud';
  5. import Debounce from 'lodash-decorators/debounce';
  6. import Bind from 'lodash-decorators/bind';
  7. import styles from './index.less';
  8. /* eslint no-underscore-dangle: 0 */
  9. /* eslint no-param-reassign: 0 */
  10. const imgUrl = 'https://gw.alipayobjects.com/zos/rmsportal/gWyeGLCdFFRavBGIDzWk.png';
  11. class TagCloud extends PureComponent {
  12. componentDidMount() {
  13. this.initTagCloud();
  14. this.renderChart();
  15. window.addEventListener('resize', this.resize);
  16. }
  17. componentWillReceiveProps(nextProps) {
  18. if (this.props.data !== nextProps.data) {
  19. this.renderChart(nextProps.data);
  20. }
  21. }
  22. componentWillUnmount() {
  23. window.removeEventListener('resize', this.resize);
  24. this.renderChart.cancel();
  25. }
  26. resize = () => {
  27. this.renderChart();
  28. }
  29. initTagCloud = () => {
  30. const { Util, Shape } = G2;
  31. function getTextAttrs(cfg) {
  32. const textAttrs = Util.mix(true, {}, {
  33. fillOpacity: cfg.opacity,
  34. fontSize: cfg.size,
  35. rotate: cfg.origin._origin.rotate,
  36. // rotate: cfg.origin._origin.rotate,
  37. text: cfg.origin._origin.text,
  38. textAlign: 'center',
  39. fill: cfg.color,
  40. textBaseline: 'Alphabetic',
  41. }, cfg.style);
  42. return textAttrs;
  43. }
  44. // 给point注册一个词云的shape
  45. Shape.registShape('point', 'cloud', {
  46. drawShape(cfg, container) {
  47. cfg.points = this.parsePoints(cfg.points);
  48. const attrs = getTextAttrs(cfg);
  49. const shape = container.addShape('text', {
  50. attrs: Util.mix(attrs, {
  51. x: cfg.points[0].x,
  52. y: cfg.points[0].y,
  53. }),
  54. });
  55. return shape;
  56. },
  57. });
  58. }
  59. saveRootRef = (node) => {
  60. this.root = node;
  61. }
  62. saveNodeRef = (node) => {
  63. this.node = node;
  64. }
  65. @Bind()
  66. @Debounce(500)
  67. renderChart(newData) {
  68. const data = newData || this.props.data;
  69. if (!data || data.length < 1) {
  70. return;
  71. }
  72. const colors = ['#1890FF', '#41D9C7', '#2FC25B', '#FACC14', '#9AE65C'];
  73. const height = this.props.height * 4;
  74. let width = 0;
  75. if (this.root) {
  76. width = this.root.offsetWidth * 4;
  77. }
  78. data.sort((a, b) => b.value - a.value);
  79. const max = data[0].value;
  80. const min = data[data.length - 1].value;
  81. // 构造一个词云布局对象
  82. const layout = new Cloud({
  83. words: data,
  84. width,
  85. height,
  86. rotate: () => 0,
  87. // 设定文字大小配置函数(默认为12-24px的随机大小)
  88. size: words => (((words.value - min) / (max - min)) * 50) + 30,
  89. // 设定文字内容
  90. text: words => words.name,
  91. });
  92. layout.image(imgUrl, (imageCloud) => {
  93. // clean
  94. if (this.node) {
  95. this.node.innerHTML = '';
  96. }
  97. // 执行词云布局函数,并在回调函数中调用G2对结果进行绘制
  98. imageCloud.exec((texts) => {
  99. const chart = new G2.Chart({
  100. container: this.node,
  101. width,
  102. height,
  103. plotCfg: {
  104. margin: 0,
  105. },
  106. });
  107. chart.legend(false);
  108. chart.axis(false);
  109. chart.tooltip(false);
  110. chart.source(texts);
  111. // 将词云坐标系调整为G2的坐标系
  112. chart.coord().reflect();
  113. chart
  114. .point()
  115. .position('x*y')
  116. .color('text', colors)
  117. .size('size', size => size)
  118. .shape('cloud')
  119. .style({
  120. fontStyle: texts[0].style,
  121. fontFamily: texts[0].font,
  122. fontWeight: texts[0].weight,
  123. });
  124. chart.render();
  125. });
  126. });
  127. }
  128. render() {
  129. return (
  130. <div
  131. className={classNames(styles.tagCloud, this.props.className)}
  132. ref={this.saveRootRef}
  133. style={{ width: '100%' }}
  134. >
  135. <div ref={this.saveNodeRef} style={{ height: this.props.height }} />
  136. </div>
  137. );
  138. }
  139. }
  140. export default TagCloud;