src/components/charts/column/column.vue (203 lines of code) (raw):
<!-- eslint-disable vue/multi-word-component-names -->
<script>
import merge from 'lodash/merge';
import {
defaultChartOptions,
grid,
gridWithSecondaryYAxis,
yAxis,
dataZoomAdjustments,
mergeSeriesToOptions,
generateBarSeries,
generateLineSeries,
} from '../../../utils/charts/config';
import {
CHART_TYPE_LINE,
HEIGHT_AUTO_CLASSES,
CHART_DEFAULT_SERIES_STACK,
CHART_DEFAULT_SERIES_SECONDARY_STACK,
} from '../../../utils/charts/constants';
import { colorFromDefaultPalette } from '../../../utils/charts/theme';
import Chart from '../chart/chart.vue';
import ChartTooltip from '../shared/tooltip/tooltip.vue';
const yAxisDefaults = {
...yAxis,
nameLocation: 'center',
axisTick: {
show: false,
},
};
export default {
name: 'GlColumnChart',
components: {
Chart,
ChartTooltip,
},
inheritAttrs: false,
props: {
bars: {
type: Array,
required: false,
default: () => [],
},
lines: {
type: Array,
required: false,
default: () => [],
},
secondaryData: {
type: Array,
required: false,
default: () => [],
},
option: {
type: Object,
required: false,
default: () => ({}),
},
yAxisTitle: {
type: String,
required: true,
},
secondaryDataTitle: {
type: String,
required: false,
default: '',
},
xAxisTitle: {
type: String,
required: true,
},
xAxisType: {
type: String,
required: true,
validator: (value) => ['value', 'category', 'time', 'log'].indexOf(value) !== -1,
},
/**
* Sets the chart's height in pixels. Set to `"auto"` to use the height of the container.
*/
height: {
type: [Number, String],
required: false,
default: null,
},
},
data() {
return {
chart: null,
};
},
computed: {
hasSecondaryAxis() {
return Boolean(this.secondaryData.length);
},
barSeries() {
return this.bars.map(({ name, data, stack = CHART_DEFAULT_SERIES_STACK }, index) => {
const color = colorFromDefaultPalette(index);
return generateBarSeries({ name, data, stack, color });
});
},
lineSeries() {
const offset = this.bars.length;
return this.lines.map(({ name, data }, index) => {
const color = colorFromDefaultPalette(offset + index);
return generateLineSeries({ name, data, color });
});
},
secondarySeries() {
const offset = this.bars.length + this.lines.length;
return this.secondaryData.map(
({ name, data, type, stack = CHART_DEFAULT_SERIES_SECONDARY_STACK }, index) => {
const color = colorFromDefaultPalette(offset + index);
return type === CHART_TYPE_LINE
? generateLineSeries({ color, name, data, yAxisIndex: 1 })
: generateBarSeries({ color, name, data, yAxisIndex: 1, stack });
}
);
},
series() {
return [...this.barSeries, ...this.lineSeries, ...this.secondarySeries];
},
options() {
const yAxisPrimary = {
...yAxisDefaults,
name: this.yAxisTitle,
};
const mergedOptions = merge(
{},
defaultChartOptions,
{
grid: this.hasSecondaryAxis ? gridWithSecondaryYAxis : grid,
xAxis: {
boundaryGap: true,
axisLabel: {
margin: 20,
verticalAlign: 'bottom',
},
axisLine: {
show: false,
},
axisPointer: {
type: 'none',
},
name: this.xAxisTitle,
type: this.xAxisType,
},
yAxis: this.hasSecondaryAxis
? [
yAxisPrimary,
{
...yAxisDefaults,
name: this.secondaryDataTitle,
show: this.hasSecondaryAxis,
},
]
: yAxisPrimary,
},
this.option,
dataZoomAdjustments(this.option.dataZoom)
);
// All chart options can be merged but series
// needs to be handled specially
return mergeSeriesToOptions(mergedOptions, this.series);
},
autoHeight() {
return this.height === 'auto';
},
},
methods: {
onCreated(chart) {
this.chart = chart;
this.$emit('created', chart);
},
},
HEIGHT_AUTO_CLASSES,
};
</script>
<template>
<div class="gl-relative" :class="{ [$options.HEIGHT_AUTO_CLASSES]: autoHeight }">
<chart
v-bind="$attrs"
:class="{ 'gl-grow': autoHeight }"
:height="height"
:options="options"
v-on="$listeners"
@created="onCreated"
/>
<chart-tooltip
v-if="chart"
ref="dataTooltip"
:chart="chart"
:use-default-tooltip-formatter="true"
>
<template v-if="$scopedSlots['tooltip-title']" #title="scope">
<slot name="tooltip-title" v-bind="scope"></slot>
</template>
<template v-if="$scopedSlots['tooltip-content']" #default="scope">
<slot name="tooltip-content" v-bind="scope"></slot>
</template>
<template v-if="$scopedSlots['tooltip-value']" #tooltip-value="scope">
<slot name="tooltip-value" v-bind="scope"></slot>
</template>
</chart-tooltip>
</div>
</template>