<template> <div class="CustomerRechargeChart"> <div id='CustomerRechargeChart' :style="`height: ${height}px;width: ${width?width+'px':'auto'}`" ></div> <div id='CustomerRechangeSlider'></div> <!-- <CustomerRechangeSlider class="CustomerRechangeSlider" :data="data" :span="4" :onChange="wheelHandle" /> --> </div> </template> <script> import G2 from '@antv/g2'; import Slider from '@antv/g2-plugin-slider'; import chartMixin from '../chartMixin'; import DataSet from '@antv/data-set'; import _ from 'lodash'; // import CustomerRechangeSlider from './slider'; const Shape = G2.Shape; const Util = G2.Util; const Global = G2.Global; function getRectRange(points, step) { var xValues = []; var yValues = []; for (var i = 0, len = points.length; i < len; i++) { var point = points[i]; xValues.push(point.x); yValues.push(point.y - step); } var xMin = Math.min.apply(null, xValues); var yMin = Math.min.apply(null, yValues); var xMax = Math.max.apply(null, xValues); var yMax = Math.max.apply(null, yValues); return { x: xMin, y: yMin, width: xMax - xMin, height: yMax - yMin, }; } // 左侧柱子 Shape.registerShape('interval', 'left', { draw: function draw(cfg, container) { var points = this.parsePoints(cfg.points); var style = Util.mix(Global.shape.interval, cfg.style, { fill: cfg.color }); var rectCfg = getRectRange(points, cfg.size / 2); // cfg.size 对应 .size(25) return container.addShape('rect', { className: 'interval', attrs: Util.mix(rectCfg, style), }); }, }); // 右侧柱子 Shape.registerShape('interval', 'right', { draw: function draw(cfg, container) { var points = this.parsePoints(cfg.points); var style = Util.mix(Global.shape.interval, cfg.style, { fill: cfg.color }); var rectCfg = getRectRange(points, -cfg.size / 2); // cfg.size 对应 .size(25) return container.addShape('rect', { className: 'interval', attrs: Util.mix(rectCfg, style), }); }, }); export default { name: 'CustomerRechargeChart', // components: { CustomerRechangeSlider }, mixins: [chartMixin], props: { rechargeCount: { type: Object, }, }, data() { return { demoList: [ { areaName: 'bvs', rechargeMoney: 13.45, rechargeMen: 12 }, { areaName: 'gsn', rechargeMoney: 23.45, rechargeMen: 13 }, { areaName: 'dsf', rechargeMoney: 12.45, rechargeMen: 16 }, { areaName: 'bzx', rechargeMoney: 45.45, rechargeMen: 63 }, { areaName: 'bvmf', rechargeMoney: 3213.454, rechargeMen: 32 }, { areaName: 'swer', rechargeMoney: 256, rechargeMen: 125 }, { areaName: 'cvsdf', rechargeMoney: 541, rechargeMen: 14 }, { areaName: 'cvsdf', rechargeMoney: 10.15, rechargeMen: 574 }, ], slider: null, sliderDom: null, ds: null, dv: null, SelectedDataIndex: null, }; }, computed: { dataList() { return this.data.map((item, index, array) => ({ ...item, index: index, scaleValue: array.length - 1 ? index / (array.length - 1) : 0, })); }, }, methods: { initData() { let start = this.dataList.length - 4 >= 0 ? (this.dataList.length - 4) / this.dataList.length : 0; let end = 1; this.ds = new DataSet({ state: { start: start, end: end, }, }); const dv = this.ds.createView().source(this.dataList); this.dv = dv; // dv.transform({ // type: 'map', // callback(row, index) { // // 加工数据后返回新的一行,默认返回行数据本身 // row.index = index; // return row; // }, // }); dv.transform({ type: 'filter', callback: obj => { const currentRadio = obj.scaleValue; return ( currentRadio >= this.ds.state.start && currentRadio <= this.ds.state.end ); }, }); this.chart = new G2.Chart({ container: 'CustomerRechargeChart', forceFit: true, height: this.height, padding: [30, 90, 20, 120], }); this.chart.source(dv, { rechargeMoney: { alias: '充值金额', }, rechargeMen: { alias: '充值笔数', }, }); this.chart.axis('areaName', { label: { offsetX: -80, htmlTemplate: (text, item, index) => { return `<div class="CustomerRechargeChart-areaTitle">${text}</div>`; }, }, }); this.chart.axis('rechargeMoney', { grid: null, }); this.chart.axis('rechargeMen'); this.chart.coord().transpose(); this.chart .interval() .position('areaName*rechargeMoney') .color('#4e82fb') .shape('left') .size(15); this.chart .interval() .position('areaName*rechargeMen') .shape('right') .color('#26c9a8') .size(15); this.chart.legend(false); this.chart.guide().text({ top: true, position: ['100%', '0%'], content: '(笔)', offsetX: 30, offsetY: -8, }); this.chart.guide().text({ top: true, position: ['100%', '100%'], content: '(元)', offsetX: 30, offsetY: 8, }); this.chart.render(); this.initSlider(); }, initSlider() { const wrapDom = document.getElementById('CustomerRechargeChart'); // let height = wrapDom.clientHeight; // const arrLength = this.data.length; // let spanNum = 4 / arrLength; this.sliderDom = document.getElementById('CustomerRechangeSlider'); this.sliderDom.style = `height:${this.height}px`; const spanNum = 4 / this.dataList.length; this.slider = new Slider({ container: this.sliderDom, // dom 容器 id 或者 dom 容器对象 width: 26, // slider 的宽度,默认为 'auto',即自适应宽度 height: this.height, // slider 的高度,默认为 '26px' padding: [20, 0, 20, 0], xAxis: 'rechargeMen', // 背景图的横轴对应字段,同时为数据筛选的字段 yAxis: 'scaleValue', // 背景图的纵轴对应字段 start: 0, end: 3 / this.dataList.length, minSpan: spanNum, maxSpan: spanNum, data: this.dataList, // slider 的数据源 textStyle: { display: 'none', }, handleStyle: { img: require('@/assets/images/dashboard/QXtfhORGlDuRvLXFzpsQ.png'), width: 26, height: 5, }, onChange: ({ startValue, endValue }) => { this.ds.setState('start', startValue); this.ds.setState('end', endValue); }, // 更新数据状态量的回调函数 }); this.slider.layout = 'vertical'; this.slider.render(); // 渲染 }, updateSlider() { this.sliderDom.innerHTML = ''; const arrLength = this.dataList.length; let start = this.dataList.length - 4 >= 0 ? (this.dataList.length - 4) / this.dataList.length : 0; let end = 1; // console.log('2222', this.dataList.length - 1, start, end); const spanNum = 4 / this.dataList.length; if (arrLength) { this.slider = new Slider({ container: this.sliderDom, width: 26, height: this.height, padding: [20, 0, 20, 0], xAxis: 'rechargeMoney', yAxis: 'scaleValue', scales: { scaleValue: { formatter: val => { let indexValue = val * (this.dataList.length - 1); // console.log(val, indexValue); return parseInt(indexValue, 10); }, }, }, start: start, end: end, minSpan: spanNum, maxSpan: spanNum, data: this.dataList, handleStyle: { img: require('@/assets/images/dashboard/QXtfhORGlDuRvLXFzpsQ.png'), width: 26, height: 5, }, onChange: ({ startValue, endValue }) => { // console.log('update:', startValue, endValue); this.ds.setState('start', startValue); this.ds.setState('end', endValue); }, }); this.slider.layout = 'vertical'; this.slider.render(); } }, refreshData() { if (this.chart) { const arrLength = this.data.length; let spanNum = 4 / arrLength; let start = this.dataList.length - 4 >= 0 ? (this.dataList.length - 4) / this.dataList.length : 0; let end = 1; this.ds.setState('start', start); this.ds.setState('end', end); this.dv.source(this.dataList); this.updateSlider(); this.updateData(); // console.log(this.chart.getYScales()); } else { this.initData(); this.initSlider(); } }, wheelHandle({ startRadio, endRadio }) { const tStartRadio = Math.abs(1 - endRadio); const sEndRadio = Math.abs(1 - startRadio); console.log(tStartRadio, sEndRadio); this.ds.setState('startRadio', tStartRadio); this.ds.setState('endRadio', sEndRadio); }, }, }; </script> <style lang="scss"> .CustomerRechargeChart { position: relative; #CustomerRechargeChart { width: 100%; // overflow-x: hidden; // overflow-y: auto; } .CustomerRechangeSlider { position: absolute; top: 0; right: 0; width: 28px; height: 100%; background-color: #eee; } #CustomerRechangeSlider { margin-left: -30px; width: 100%; height: 300px; transform: translate(100%, -100%); } .CustomerRechargeChart-areaTitle { color: #666; width: 85px; height: 2.4em; line-height: 1.2; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } } </style>