antV f2 windowResize
思路:①注册全局总线 提起监听事件;
②在app.vue的入口页写下监听事件,顺便带上防抖;
③在组件里面用f2的chart changeSize事件让视图重绘
注册总线 mian.js
Vue.prototype.$eventBus = new Vue();
Vue.config.productionTip = false;
App.vue 入口页 监听注册总线
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
import '@/util/common';
import { mapActions } from 'vuex';
export default {
name: 'App',
data () {
return {
fn: null,
};
},
mounted () {
this.fn = this.debounce(this.handle, 100);
window.addEventListener('resize', this.fn);
this.initUserFollows();
},
beforeDestroy () {
window.removeEventListener('resize', this.fn);
this.fn = null;
},
methods: {
debounce (fn, wait) {
let timeout = null;
return function () {
if (timeout !== null) clearTimeout(timeout);
timeout = setTimeout(fn, wait);
};
},
handle () {
this.$eventBus.$emit('windowResize');
},
},
};
</script>
<style lang="scss">@import 'styles/global.scss';
</style>
tool.js 封装 changeSize方法
const fixWindowSize = (canvas, chart) => {
canvas.style.width = '100%';
canvas.style.height = '100%';
canvas.removeAttribute('width');
canvas.removeAttribute('height');
const w = canvas.offsetWidth;
const h = canvas.offsetHeight;
chart.changeSize(w, h);
};
export {
fixWindowSize,
};
利用antV f2封装的绘画组件 同时在mounted周期里面添加eventBus['windowResize']
<template>
<div class="chart-canvas-box">
<canvas ref="chart-canvas" />
</div>
</template>
<script>
import F2 from '@antv/f2';
import _ from 'lodash';
import { fixWindowSize } from '@/util/tool';
export default {
name: 'Bar',
props: {
data: {
type: Array,
default: () => [],
},
props: {
type: Object,
default: () => {},
},
type: {
type: String,
default: 'base', // base 基础柱状图, group 分组柱状图, stack 层叠柱状图
},
position: {
type: String,
default: 'bottom',
},
// 图表绘图区域和画布边框的间距,用于显示坐标轴文本、图例,
// 默认值 'auto',自动计算
// [0, 10, 40, 100],分别设置上、右、下、左边距
padding: {
type: Array,
default: () => [],
},
// 坐标系是否翻转
transposed: {
type: Boolean,
default: false,
},
// 是否需要显示单位
showGuideText: {
type: Boolean,
default: false,
},
barRadius: {
type: Number,
default: 3,
},
barSize: {
type: Number,
default: 0,
},
// 刻度
// ticks: {
// type: Array,
// default: () => [],
// },
// 范围
rangeConfig: {
type: Object,
default: () => {},
},
tooltipConfig: {
type: Object,
default: () => {},
},
// Y轴单位-上下左右偏移数值
offsetX: {
type: Number,
default: -28,
},
offsetY: {
type: Number,
default: -30,
},
legendOffsetY:{
type: Number,
default: 0,
},
tooltipLegendShow: {
type: Boolean,
default: false,
},
},
data () {
return {
chart: null,
keyPondDefault: {
label: 'label',
value: 'value',
unit: 'unit',
latitude: 'latitude',
color: 'color',
},
colorList: [],
guide: null,
valueGuide: [],
};
},
computed: {
keyPond () {
return Object.assign(this.keyPondDefault, this.props);
},
},
watch: {
data (val) {
this.chartRender();
},
// padding (val) {
// this.chartRender();
// },
},
created () {
},
mounted () {
this.chartRender();
this.$eventBus.$on('windowResize', () => {
fixWindowSize(this.$refs['chart-canvas'], this.chart);
});
},
beforeDestroy () {
this.$eventBus.$off('windowResize');
},
methods: {
chartRender () {
// if (!this.data) return;
// if (this.data.length === 0) return;
this.chart && this.chart.clear();
this.chart = null;
this.transColorList();
this.chart = new F2.Chart({
el: this.$refs['chart-canvas'],
pixelRatio: window.devicePixelRatio,
padding: this.padding.length > 0 ? this.padding : 'auto',
appendPadding: [20, 10, 10, 10],
});
this.chart.source(this.data, {
[this.keyPond.value]: {
// ticks: this.ticks,
...this.rangeConfig,
},
});
// 显示柱状图的数量
if (this.showGuideText) {
if (this.type === 'stack') {
let stackList = this.transStackData();
// console.log(stackList);
stackList.forEach((obj, index) => {
this.createValueGuideText(obj);
});
} else {
this.data.forEach((obj, index) => {
// this.valueGuide[index] = this.createValueGuideText(obj);
this.createValueGuideText(obj);
});
}
}
// 坐标系是否翻转
this.chart.coord({
transposed: this.transposed,
});
const dataItem = this.data[0];
// console.log((dataItem && dataItem[this.keyPond.unit]) || 'null', '创建chart');
if (dataItem && dataItem[this.keyPond.unit] !== '' && !this.transposed) {
this.guide = this.chart.guide().text({
top: true,
position: [ '0%', '0%' ],
content: this.data[0][this.keyPond.unit],
style: {
textAlign: 'start',
textBaseline: 'top',
fill: '#999',
},
offsetX: this.offsetX,
offsetY: this.offsetY,
});
}
this.chart.legend({ position: this.position, clickable: false, offsetY: this.legendOffsetY, });
const areaStr = `${this.keyPond.label}*${this.keyPond.value}`;
const chartConfig = this.chart.interval().position(areaStr).style({
radius: this.barRadius,
});
if (this.barSize) {
chartConfig.size(this.barSize);
}
switch (this.type) {
case 'group':
if (this.tooltipLegendShow) {
this.chart.tooltip(this.tooltipLegend());
} else {
this.chart.tooltip(this.tooltipConfig);
}
chartConfig.color(this.keyPond.latitude, this.colorList).adjust({
type: 'dodge',
marginRatio: 0.05, // 设置分组间柱子的间距
});
break;
case 'stack':
this.chart.tooltip(this.tooltipConfig);
chartConfig.color(this.keyPond.latitude, this.colorList).adjust('stack');
break;
default :
this.chart.tooltip(this.tooltipConfig);
// this.chart.interval().position(areaStr);
break;
}
this.chart.render();
},
tooltipDefault () {
return {
showItemMarker: false,
onShow: (ev) => {
const item = ev.items[0];
item.name = item.title;
item.value = item.value + item.origin[this.keyPond.unit];
},
};
},
tooltipLegend () {
return {
custom: true, // 自定义 tooltip 内容框
onChange: (obj) => {
const legend = this.chart.get('legendController').legends[this.position][0];
const tooltipItems = obj.items;
const legendItems = legend.items;
const map = {};
legendItems.forEach(function (item) {
map[item.name] = _.clone(item);
});
tooltipItems.forEach((item) => {
const name = item.name;
const value = item.value;
if (map[name]) {
map[name].value = value;
}
});
legend.setItems(_.values(map));
},
onHide: () => {
const legend = this.chart.get('legendController').legends[this.position][0];
legend.setItems(this.chart.getLegendItems().country);
},
};
},
transColorList () {
const list = [];
const map = {};
if (this.type === 'group' || this.type === 'stack') {
this.data.forEach(element => {
const key = element[this.keyPond.latitude];
if (!map[key]) {
if (element[this.keyPond.color]) {
map[key] = element[this.keyPond.color];
list.push(element[this.keyPond.color]);
}
}
});
} else {
this.data.forEach(element => {
if (element[this.keyPond.color]) list.push(element[this.keyPond.color]);
});
}
// for (const key in map) {
// if (map.hasOwnProperty(key)) {
// const element = map[key];
// list.push(element);
// }
// }
this.colorList = list.length > 0 ? list : null;
},
setGuideText () {
if (this.chart && this.guide && this.data[0][this.keyPond.unit] !== '') {
this.guide.content = this.data[0][this.keyPond.unit];
this.guide.repaint();
}
},
updateValueGuide () {
this.data.forEach((item, index) => {
if (!this.valueGuide[index]) this.valueGuide[index] = this.createValueGuideText(item);
this.valueGuide[index].content = this.data[index][this.keyPond.value];
this.valueGuide[index].repaint();
});
},
createValueGuideText (item) {
return this.chart.guide().text({
position: [item[this.keyPond.label], item[this.keyPond.value]],
content: item[this.keyPond.value],
style: {
textBaseline: 'bottom',
textAlign: 'center',
fill: '#A1ABB3',
},
offsetY: -8,
});
},
transStackData () {
const arr = [];
const obj = {};
for (let index = 0; index < this.data.length; index++) {
const element = this.data[index];
const label = element[this.keyPond.label];
if (!obj[label]) {
obj[label] = Object.assign({}, element);
} else {
obj[label][this.keyPond.value] += element[this.keyPond.value];
}
}
// console.log(obj);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const element = obj[key];
arr.push(element);
}
}
return arr;
},
},
};
</script>
<style lang="scss" scoped>
.chart-canvas-box {
width: 100%;
height: 100%;
& > canvas {
width: 100%;
height: 100%;
}
}
</style>
视图组件引用
<bar class="bar-style" :data="listData" :bar-size="30" :ticks="[0,100,200]" />
<bar class="bar-style" :data="colorData" />
<bar class="bar-style" :data="manyData" :props="barProps" type="group" />
<bar class="bar-style" :data="manyData" :props="barProps" type="stack" />
数据json
listData: [
{
label: '城区',
value: 58,
unit: '万人',
},
{
label: '陆丰市',
value: 188,
unit: '万人',
},
{
label: '海丰县',
value: 85,
unit: '万人',
},
{
label: '陆河县',
value: 36,
unit: '万人',
},
],
uncertainData: [
{
name: '城区',
val: 58,
str: '万人',
status: '严重',
},
{
name: '陆丰市',
val: 188,
str: '万人',
status: '重度',
},
{
name: '海丰县',
val: 85,
str: '万人',
status: '中度',
},
{
name: '陆河县',
val: 36,
str: '万人',
status: '轻度',
},
],
manyData: [
{
years: '2008',
name: '城区',
val: 50,
str: '万人',
},
{
years: '2008',
name: '陆丰市',
val: 94,
str: '万人',
},
{
years: '2008',
name: '海丰县',
val: 102,
str: '万人',
},
{
years: '2008',
name: '陆河县',
val: 51,
str: '万人',
},
{
years: '2018',
name: '城区',
val: 58,
str: '万人',
},
{
years: '2018',
name: '陆丰市',
val: 188,
str: '万人',
},
{
years: '2018',
name: '海丰县',
val: 85,
str: '万人',
},
{
years: '2018',
name: '陆河县',
val: 36,
str: '万人',
},
],
barProps: {
label: 'name',
value: 'val',
unit: 'str',
latitude: 'years',
status: 'status',
},
colorData: [
{
label: '城区',
value: 58,
unit: '万人',
color: '#687DF6',
},
{
label: '陆丰市',
value: 188,
unit: '万人',
color: '#687DF6',
},
{
label: '海丰县',
value: 85,
unit: '万人',
color: '#687DF6',
},
{
label: '陆河县',
value: 36,
unit: '万人',
color: '#687DF6',
},
],
网友评论