95b43b74a5cbf7df6c4ab96953268d4fa1ae2610.svn-base 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <template>
  2. <div :style="{ padding: '0 0 32px 32px' }">
  3. <h4 :style="{ marginBottom: '20px' }">{{ title }}</h4>
  4. <v-chart :force-fit="true" :height="height" :data="data" :scale="scale" :width="width" :padding="padding" :onClick="handleClick">
  5. <v-tooltip :show-title="false" :item-tpl="tooltipOpts.itemTpl" />
  6. <v-legend />
  7. <v-coord type="rect" direction="LT" />
  8. <v-pyramid :position="funnelOpts.position" :color="funnelOpts.color" :label="funnelOpts.label" :tooltip="funnelOpts.tooltip" />
  9. <v-guide v-for="(obj, index) in data"
  10. type="text"
  11. :key="index"
  12. :top="true"
  13. :position="getPosition(obj)"
  14. :content="getContent(obj)"
  15. :vStyle="style"
  16. />
  17. </v-chart>
  18. </div>
  19. </template>
  20. <script>
  21. import { DataSet } from '@antv/data-set'
  22. import { ChartEventMixins } from './mixins/ChartMixins'
  23. export default {
  24. mixins: [ChartEventMixins],
  25. props: {
  26. title: {
  27. type: String,
  28. default: ''
  29. },
  30. height: {
  31. type: Number,
  32. default: 254
  33. },
  34. width: {
  35. type: Number,
  36. default: 254
  37. },
  38. field: {
  39. type: String,
  40. default: 'count'
  41. },
  42. xField: {
  43. type: String,
  44. default: 'action'
  45. },
  46. dataSource: {
  47. type: Array,
  48. default: () => [
  49. { action: '浏览网站', pv: 50000 },
  50. { action: '放入购物车', pv: 35000 },
  51. { action: '生成订单', pv: 25000 },
  52. { action: '支付订单', pv: 15000 },
  53. { action: '完成交易', pv: 8000 }
  54. ]
  55. }
  56. },
  57. data() {
  58. return {
  59. padding: [20, '20%', 60, '20%'],
  60. tooltipOpts: {
  61. showTitle: false,
  62. itemTpl: '<li data-index={index} style="margin-bottom:4px;">' +
  63. '<span style="background-color:{color};" class="g2-tooltip-marker"></span>' +
  64. '{name}<br/>' +
  65. '<span style="padding-left: 16px">{name}:{pv}</span><br/>' +
  66. '<span style="padding-left: 16px">占比:{percent}</span><br/>' +
  67. '</li>'
  68. },
  69. scale: {
  70. dataKey: 'percent',
  71. nice: false
  72. },
  73. funnelOpts: {
  74. position: this.xField + '*percent',
  75. color: [this.xField, ['#0050B3', '#1890FF', '#40A9FF', '#69C0FF', '#BAE7FF']],
  76. label: [this.xField + '*' + this.field, (action, pv) => {
  77. return action + ' ' + pv
  78. }, {
  79. offset: 35,
  80. labelLine: {
  81. lineWidth: 1,
  82. stroke: 'rgba(0, 0, 0, 0.15)'
  83. }
  84. }],
  85. tooltip: [this.xField + '*' + this.field + '*percent', (action, pv, percent) => ({
  86. name: action,
  87. percent: Math.floor(percent * 100) + '%',
  88. pv: pv
  89. })]
  90. },
  91. style: {
  92. fill: '#fff',
  93. fontSize: '12',
  94. textAlign: 'center',
  95. shadowBlur: 2,
  96. shadowColor: 'rgba(0, 0, 0, .45)'
  97. }
  98. }
  99. },
  100. methods: {
  101. getPosition: (obj) => {
  102. return {
  103. action: obj.action,
  104. percent: 'median'
  105. }
  106. },
  107. getContent: (obj) => {
  108. return parseInt(String(obj.percent * 100)) + '%'
  109. }
  110. },
  111. computed: {
  112. data() {
  113. const that = this
  114. const dv = new DataSet.View().source(this.dataSource)
  115. dv.transform({
  116. type: 'percent',
  117. field: this.field,
  118. dimension: this.xField,
  119. as: 'percent'
  120. })
  121. dv.transform({
  122. type: 'sort',
  123. callback(a, b) {
  124. return b[that.field] - a[that.field]
  125. }
  126. })
  127. return dv.rows
  128. }
  129. }
  130. }
  131. </script>