fix(图表):双轴类型图表无法根据维度进行自定义颜色

This commit is contained in:
ulleo 2024-08-01 14:34:37 +08:00
parent b97c3e54ae
commit 13a1d1f8eb
7 changed files with 880 additions and 62 deletions

View File

@ -1,6 +1,7 @@
declare type EditorProperty =
| 'background-overall-component'
| 'basic-style-selector'
| 'dual-basic-style-selector'
| 'label-selector'
| 'tooltip-selector'
| 'x-axis-selector'

View File

@ -14,6 +14,7 @@ import { storeToRefs } from 'pinia'
import CollapseSwitchItem from '@/components/collapse-switch-item/src/CollapseSwitchItem.vue'
import { ElCollapse, ElCollapseItem } from 'element-plus-secondary'
import BasicStyleSelector from '@/views/chart/components/editor/editor-style/components/BasicStyleSelector.vue'
import DualBasicStyleSelector from '@/views/chart/components/editor/editor-style/components/DualBasicStyleSelector.vue'
import ComponentPosition from '@/components/visualization/common/ComponentPosition.vue'
import BackgroundOverallCommon from '@/components/visualization/component-background/BackgroundOverallCommon.vue'
import TableHeaderSelector from '@/views/chart/components/editor/editor-style/components/table/TableHeaderSelector.vue'
@ -242,6 +243,20 @@ watch(
@onMiscChange="onMiscChange"
/>
</el-collapse-item>
<el-collapse-item
:effect="themes"
name="basicStyle"
:title="t('chart.basic_style')"
v-if="showProperties('dual-basic-style-selector')"
>
<DualBasicStyleSelector
:property-inner="propertyInnerAll['dual-basic-style-selector']"
:themes="themes"
:chart="chart"
@onBasicStyleChange="onBasicStyleChange"
@onMiscChange="onMiscChange"
/>
</el-collapse-item>
<collapse-switch-item
:themes="themes"
v-model="chart.customStyle.text.show"

View File

@ -24,9 +24,11 @@ const props = withDefaults(
}
propertyInner: Array<string>
chart: ChartObj
sub?: boolean
}>(),
{
themes: 'light'
themes: 'light',
sub: false
}
)
const dvMainStore = dvMainStoreWithOut()
@ -34,7 +36,7 @@ const { batchOptStatus } = storeToRefs(dvMainStore)
const emits = defineEmits(['update:modelValue', 'changeBasicStyle'])
const changeChartType = () => {
if (isColorGradient.value) {
state.value.basicStyleForm.colorScheme = 'default'
state.value.basicStyleForm[colorSchemeName.value] = 'default'
changeColorOption({ value: 'default' })
}
}
@ -50,28 +52,79 @@ const seriesColorState = reactive({
curColorIndex: 0,
seriesColorPickerId: 'body'
})
const instance = ref<G2PlotChartView | undefined>()
const colorsName = computed(() => {
return props.sub ? 'subColors' : 'colors'
})
const colorSchemeName = computed(() => {
return props.sub ? 'subColorScheme' : 'colorScheme'
})
const seriesColorName = computed(() => {
return props.sub ? 'subSeriesColor' : 'seriesColor'
})
const needSetSeriesColor = computed(() => {
return (
instance.value?.propertyInner?.['basic-style-selector']?.includes('seriesColor') ||
instance.value?.propertyInner?.['dual-basic-style-selector']?.includes('seriesColor')
)
})
const needSetSubSeriesColor = computed(() => {
return instance.value?.propertyInner?.['dual-basic-style-selector']?.includes('subSeriesColor')
})
const setupSeriesColor = () => {
if (batchOptStatus.value || !props.chart) {
return
}
const instance = chartViewManager.getChartView(
instance.value = chartViewManager.getChartView(
props.chart.render,
props.chart.type
) as G2PlotChartView
if (!instance?.propertyInner?.['basic-style-selector'].includes('seriesColor')) {
return
if (!props.sub) {
if (!needSetSeriesColor.value) {
return
}
} else {
if (!needSetSubSeriesColor.value) {
return
}
}
const viewData = dvMainStore.getViewOriginData(props.chart.id)
let viewData = dvMainStore.getViewOriginData(props.chart.id)
if (!viewData) {
return
}
const newSeriesColor = instance.setupSeriesColor(props.chart, viewData.data)
if (props.chart.type.includes('chart-mix')) {
if (props.sub) {
viewData = viewData.right?.data?.[0]
} else {
viewData = viewData.left?.data?.[0]
}
}
if (!viewData) {
return
}
const sFunction = props.sub
? instance.value?.setupSubSeriesColor
: instance.value.setupSeriesColor
if (!sFunction) {
return
}
const newSeriesColor = sFunction(props.chart, viewData.data)
const oldSeriesColor =
props.chart.customAttr.basicStyle.seriesColor?.reduce((p, n) => {
props.chart.customAttr.basicStyle[seriesColorName.value]?.reduce((p, n) => {
p[n.id] = n
return p
}, {}) || {}
newSeriesColor?.forEach(item => {
const oldColorItem = oldSeriesColor[item.id]
if (oldColorItem) {
@ -116,7 +169,7 @@ const changeSeriesColor = () => {
}
})
if (changed) {
state.value.basicStyleForm.seriesColor = seriesColorState.seriesColor
state.value.basicStyleForm[seriesColorName.value] = seriesColorState.seriesColor
changeBasicStyle('seriesColor')
}
}
@ -154,7 +207,7 @@ const colorCaseSelectorRef = ref<InstanceType<typeof ElPopover>>()
const customColorPickerRef = ref<InstanceType<typeof ElColorPicker>>()
function selectColorCase(option) {
state.value.basicStyleForm.colorScheme = option.value
state.value.basicStyleForm[colorSchemeName.value] = option.value
colorCaseSelectorRef.value?.hide()
changeColorOption(option)
}
@ -162,13 +215,14 @@ function selectColorCase(option) {
const changeColorOption = (option?) => {
let isGradient = option?.value?.endsWith('_split_gradient') || isColorGradient.value
const getColorItems = isGradient ? getMapColorCases(colorCases) : colorCases
const items = getColorItems.filter(ele => ele.value === state.value.basicStyleForm.colorScheme)
const items = getColorItems.filter(
ele => ele.value === state.value.basicStyleForm[colorSchemeName.value]
)
if (items.length > 0) {
state.value.basicStyleForm.colors = [...items[0].colors]
state.value.customColor = state.value.basicStyleForm.colors[0]
state.value.basicStyleForm[colorsName.value] = [...items[0].colors]
state.value.customColor = state.value.basicStyleForm[colorsName.value][0]
state.value.colorIndex = 0
state.value.basicStyleForm.seriesColor?.forEach((c, i) => {
state.value.basicStyleForm[seriesColorName.value]?.forEach((c, i) => {
const length = items[0].colors.length
c.color = items[0].colors[i % length]
})
@ -181,22 +235,22 @@ const resetCustomColor = () => {
const switchColorCase = () => {
const { colorIndex, customColor, basicStyleForm } = state.value
const colors = basicStyleForm.colors
const colors = basicStyleForm[colorsName.value]
if (isColorGradient.value) {
let startColor = colorIndex === 0 ? customColor : colors[0]
let endColor = colorIndex === 0 ? colors[8] : customColor
basicStyleForm.colors = stepsColor(startColor, endColor, 9, 1)
basicStyleForm[colorsName.value] = stepsColor(startColor, endColor, 9, 1)
} else {
colors[colorIndex] = customColor
}
changeBasicStyle()
}
const isColorGradient = computed(() =>
state.value.basicStyleForm.colorScheme.endsWith('_split_gradient')
state.value.basicStyleForm[colorSchemeName.value].endsWith('_split_gradient')
)
const showColorGradientIndex = index => {
return index === 0 || index === state.value.basicStyleForm.colors.length - 1
return index === 0 || index === state.value.basicStyleForm[colorsName.value].length - 1
}
const switchColor = (index, c) => {
if (isColorGradient.value && !showColorGradientIndex(index)) {
@ -279,7 +333,7 @@ const colorItemBorderColor = (index, state) => {
<template #prefix>
<div class="custom-color-selector-container">
<div
v-for="(c, index) in state.basicStyleForm.colors"
v-for="(c, index) in state.basicStyleForm[colorsName]"
:key="index"
:style="{
flex: 1,
@ -306,7 +360,7 @@ const colorItemBorderColor = (index, state) => {
v-for="option in colorCases"
:key="option.value"
class="select-color-item"
:class="{ active: state.basicStyleForm.colorScheme === option.value }"
:class="{ active: state.basicStyleForm[colorSchemeName] === option.value }"
@click="selectColorCase(option)"
>
<div style="float: left">
@ -347,9 +401,12 @@ const colorItemBorderColor = (index, state) => {
</span>
</div>
<div v-if="!showProperty('seriesColor')" class="custom-color-extend-setting colors">
<div
v-if="!((!sub && showProperty('seriesColor')) || (sub && showProperty('subSeriesColor')))"
class="custom-color-extend-setting colors"
>
<div
v-for="(c, index) in state.basicStyleForm.colors"
v-for="(c, index) in state.basicStyleForm[colorsName]"
:key="index"
:class="{
active: state.colorIndex === index,
@ -393,7 +450,10 @@ const colorItemBorderColor = (index, state) => {
</div>
</div>
<div
v-if="showProperty('seriesColor') && !batchOptStatus"
v-if="
((!sub && showProperty('seriesColor')) || (sub && showProperty('subSeriesColor'))) &&
!batchOptStatus
"
class="series-color-setting colors"
>
<div

View File

@ -0,0 +1,420 @@
<script setup lang="ts">
import { onMounted, PropType, reactive, watch, ref } from 'vue'
import { COLOR_PANEL, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
import { useI18n } from '@/hooks/web/useI18n'
import CustomColorStyleSelect from '@/views/chart/components/editor/editor-style/components/CustomColorStyleSelect.vue'
import { cloneDeep, defaultsDeep } from 'lodash-es'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import {
CHART_MIX_DEFAULT_BASIC_STYLE,
MixChartBasicStyle
} from '@/views/chart/components/js/panel/charts/others/chart-mix-common'
const dvMainStore = dvMainStoreWithOut()
const { batchOptStatus } = storeToRefs(dvMainStore)
const { t } = useI18n()
const props = defineProps({
chart: {
type: Object as PropType<ChartObj>,
required: true
},
themes: {
type: String as PropType<EditorTheme>,
default: 'dark'
},
propertyInner: {
type: Array<string>
}
})
const showProperty = prop => props.propertyInner?.includes(prop)
const predefineColors = COLOR_PANEL
const state = reactive({
basicStyleForm: JSON.parse(JSON.stringify(CHART_MIX_DEFAULT_BASIC_STYLE)) as MixChartBasicStyle,
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr,
customColor: null,
colorIndex: 0,
fieldColumnWidth: {
fieldId: '',
width: 0
}
})
watch(
[
() => props.chart.customAttr.basicStyle,
() => props.chart.customAttr.misc,
() => props.chart.customAttr.tableHeader,
() => props.chart.xAxis,
() => props.chart.yAxis
],
() => {
init()
},
{ deep: true }
)
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
const changeBasicStyle = (prop?: string, requestData = false) => {
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData }, prop)
}
const onAlphaChange = v => {
const _v = parseInt(v)
if (_v >= 0 && _v <= 100) {
state.basicStyleForm.alpha = _v
} else if (_v < 0) {
state.basicStyleForm.alpha = 0
} else if (_v > 100) {
state.basicStyleForm.alpha = 100
} else {
const basicStyle = cloneDeep(props.chart.customAttr.basicStyle)
const oldForm = defaultsDeep(
basicStyle,
cloneDeep(CHART_MIX_DEFAULT_BASIC_STYLE)
) as ChartBasicStyle
state.basicStyleForm.alpha = oldForm.alpha
}
changeBasicStyle('alpha')
}
const onSubAlphaChange = v => {
const _v = parseInt(v)
if (_v >= 0 && _v <= 100) {
state.basicStyleForm.subAlpha = _v
} else if (_v < 0) {
state.basicStyleForm.subAlpha = 0
} else if (_v > 100) {
state.basicStyleForm.subAlpha = 100
} else {
const basicStyle = cloneDeep(props.chart.customAttr.basicStyle)
const oldForm = defaultsDeep(
basicStyle,
cloneDeep(CHART_MIX_DEFAULT_BASIC_STYLE)
) as MixChartBasicStyle
state.basicStyleForm.subAlpha = oldForm.subAlpha
}
changeBasicStyle('alpha')
}
const init = () => {
const basicStyle = cloneDeep(props.chart.customAttr.basicStyle)
const miscStyle = cloneDeep(props.chart.customAttr.misc)
configCompat(basicStyle)
state.basicStyleForm = defaultsDeep(
basicStyle,
cloneDeep(CHART_MIX_DEFAULT_BASIC_STYLE)
) as MixChartBasicStyle
state.miscForm = defaultsDeep(miscStyle, cloneDeep(DEFAULT_MISC)) as ChartMiscAttr
if (!state.customColor) {
state.customColor = state.basicStyleForm.colors[0]
state.colorIndex = 0
}
}
const configCompat = (basicStyle: ChartBasicStyle) => {
//
if (basicStyle.suspension === false && basicStyle.showZoom === undefined) {
basicStyle.showZoom = false
}
}
const symbolOptions = [
{ name: t('chart.line_symbol_circle'), value: 'circle' },
{ name: t('chart.line_symbol_rect'), value: 'square' },
{ name: t('chart.line_symbol_triangle'), value: 'triangle' },
{ name: t('chart.line_symbol_diamond'), value: 'diamond' }
]
const activeName = ref<'left' | 'right'>('left')
onMounted(() => {
init()
})
</script>
<template>
<div style="width: 100%">
<el-tabs v-model="activeName" id="axis-tabs" stretch>
<el-tab-pane :label="t('chart.yAxisLeft')" name="left">
<template v-if="showProperty('colors')">
<custom-color-style-select
v-model="state"
:chart="chart"
:themes="themes"
:property-inner="propertyInner"
@change-basic-style="prop => changeBasicStyle(prop)"
/>
</template>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
v-if="showProperty('gradient')"
>
<el-checkbox
size="small"
:effect="themes"
v-model="state.basicStyleForm.gradient"
@change="changeBasicStyle('gradient')"
>
{{ $t('chart.gradient') }}{{ $t('chart.color') }}
</el-checkbox>
</el-form-item>
<div class="alpha-setting" v-if="showProperty('alpha')">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.not_alpha') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col :span="13">
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
v-model="state.basicStyleForm.alpha"
@change="changeBasicStyle('alpha')"
/>
</el-form-item>
</el-col>
<el-col :span="11" style="padding-top: 2px">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-input
type="number"
:effect="themes"
v-model="state.basicStyleForm.alpha"
:min="0"
:max="100"
class="basic-input-number"
:controls="false"
@change="onAlphaChange"
>
<template #suffix> % </template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</div>
<el-form-item
class="form-item"
v-if="showProperty('radiusColumnBar')"
:label="t('chart.radiusColumnBar')"
:class="'form-item-' + themes"
>
<el-radio-group
size="small"
:effect="themes"
v-model="state.basicStyleForm.radiusColumnBar"
@change="changeBasicStyle('radiusColumnBar')"
>
<el-radio label="rightAngle" :effect="themes">{{ t('chart.rightAngle') }}</el-radio>
<el-radio label="roundAngle" :effect="themes">{{ t('chart.roundAngle') }}</el-radio>
</el-radio-group>
</el-form-item>
</el-tab-pane>
<el-tab-pane :label="t('chart.yAxisRight')" name="right">
<template v-if="showProperty('colors')">
<custom-color-style-select
sub
v-model="state"
:chart="chart"
:themes="themes"
:property-inner="propertyInner"
@change-basic-style="prop => changeBasicStyle(prop)"
/>
</template>
<div class="alpha-setting" v-if="showProperty('alpha')">
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
{{ t('chart.not_alpha') }}
</label>
<el-row style="flex: 1" :gutter="8">
<el-col :span="13">
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
<el-slider
:effect="themes"
v-model="state.basicStyleForm.subAlpha"
@change="changeBasicStyle('alpha')"
/>
</el-form-item>
</el-col>
<el-col :span="11" style="padding-top: 2px">
<el-form-item class="form-item" :class="'form-item-' + themes">
<el-input
type="number"
:effect="themes"
v-model="state.basicStyleForm.subAlpha"
:min="0"
:max="100"
class="basic-input-number"
:controls="false"
@change="onSubAlphaChange"
>
<template #suffix> % </template>
</el-input>
</el-form-item>
</el-col>
</el-row>
</div>
<el-row :gutter="8">
<el-col :span="12">
<el-form-item
:label="t('chart.line_width')"
class="form-item form-item-slider"
:class="'form-item-' + themes"
v-if="showProperty('lineWidth')"
>
<el-input-number
:effect="themes"
v-model="state.basicStyleForm.lineWidth"
:min="0"
:max="10"
controls-position="right"
@change="changeBasicStyle('lineWidth')"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="8">
<el-col :span="12">
<el-form-item
:label="t('chart.line_symbol')"
class="form-item"
:class="'form-item-' + themes"
v-if="showProperty('lineSymbol')"
>
<el-select
:effect="themes"
v-model="state.basicStyleForm.lineSymbol"
:placeholder="t('chart.line_symbol')"
@change="changeBasicStyle('lineSymbol')"
>
<el-option
v-for="item in symbolOptions"
:key="item.value"
:label="item.name"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
:label="t('chart.line_symbol_size')"
class="form-item form-item-slider"
:class="'form-item-' + themes"
v-if="showProperty('lineSymbolSize')"
>
<el-input-number
:effect="themes"
v-model="state.basicStyleForm.lineSymbolSize"
:min="0"
:max="20"
controls-position="right"
@change="changeBasicStyle('lineSymbolSize')"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item
class="form-item"
:class="'form-item-' + themes"
v-if="showProperty('lineSmooth')"
>
<el-checkbox
size="small"
:effect="themes"
v-model="state.basicStyleForm.lineSmooth"
@change="changeBasicStyle('lineSmooth')"
>
{{ t('chart.line_smooth') }}
</el-checkbox>
</el-form-item>
</el-tab-pane>
</el-tabs>
</div>
</template>
<style scoped lang="less">
.form-item {
}
.color-picker-style {
cursor: pointer;
z-index: 1003;
}
.alpha-setting {
display: flex;
width: 100%;
.alpha-slider {
padding: 0 8px;
:deep(.ed-slider__button-wrapper) {
--ed-slider-button-wrapper-size: 36px;
--ed-slider-button-size: 16px;
}
}
.alpha-label {
padding-right: 8px;
font-size: 12px;
font-style: normal;
font-weight: 400;
height: 32px;
line-height: 32px;
display: inline-flex;
align-items: flex-start;
min-width: 56px;
&.dark {
color: #a6a6a6;
}
}
}
.table-field-width-config {
.ed-select {
width: 100px !important;
:deep(.ed-input__wrapper) {
border-radius: 4px 0 0 4px !important;
}
}
.ed-input-group {
width: 120px;
:deep(.ed-input__wrapper) {
border-radius: 0 !important;
}
:deep(.ed-input-group__append) {
padding: 0 8px;
}
}
}
.table-column-mode {
:deep(.ed-radio) {
margin-right: 10px !important;
}
}
.basic-input-number {
:deep(input) {
-webkit-appearance: none;
-moz-appearance: textfield;
&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
-webkit-appearance: none;
}
}
}
.top-n-setting {
.ed-input-number {
width: 80px !important;
margin: 0 2px;
}
:deep(span) {
font-size: 12px;
}
}
#axis-tabs {
margin-top: -16px;
--ed-tabs-header-height: 34px;
:deep(.ed-tabs__header) {
border-top: none !important;
}
}
</style>

View File

@ -1,6 +1,8 @@
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
export const CHART_MIX_EDITOR_PROPERTY: EditorProperty[] = [
'background-overall-component',
'basic-style-selector',
'dual-basic-style-selector',
'x-axis-selector',
'dual-y-axis-selector',
'title-selector',
@ -16,7 +18,7 @@ export const CHART_MIX_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
'background-overall-component': ['all'],
'label-selector': ['fontSize', 'color'],
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'show'],
'basic-style-selector': [
'dual-basic-style-selector': [
'colors',
'alpha',
'gradient',
@ -24,7 +26,8 @@ export const CHART_MIX_EDITOR_PROPERTY_INNER: EditorPropertyInner = {
'lineSymbol',
'lineSymbolSize',
'lineSmooth',
'radiusColumnBar'
'radiusColumnBar',
'subSeriesColor'
],
'x-axis-selector': [
'name',
@ -69,3 +72,40 @@ export const CHART_MIX_AXIS_TYPE: AxisType[] = [
'extLabel',
'extTooltip'
]
export const CHART_MIX_DEFAULT_BASIC_STYLE = {
...DEFAULT_BASIC_STYLE,
subAlpha: 100,
subColorScheme: 'fast',
subSeriesColor: [],
subColors: [
'#fae800',
'#00c039',
'#0482dc',
'#bb9581',
'#ff7701',
'#9c5ec3',
'#00ccdf',
'#00c039',
'#ff7701'
]
}
export interface MixChartBasicStyle extends ChartBasicStyle {
subAlpha: number
subColors: string[]
subSeriesColor: {
/**
* 序列识别id多指标就是轴id分组或者堆叠就是类别值
*/
id: string
/**
* 显示名称
*/
name: string
/**
* 序列颜色
*/
color: string
}[]
}

View File

@ -12,16 +12,19 @@ import {
setGradientColor
} from '../../common/common_antv'
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { cloneDeep, isEmpty, defaultTo, map, filter, union, slice } from 'lodash-es'
import { cloneDeep, isEmpty, defaultTo, map, filter, union, defaultsDeep } from 'lodash-es'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import {
CHART_MIX_AXIS_TYPE,
CHART_MIX_DEFAULT_BASIC_STYLE,
CHART_MIX_EDITOR_PROPERTY,
CHART_MIX_EDITOR_PROPERTY_INNER
CHART_MIX_EDITOR_PROPERTY_INNER,
MixChartBasicStyle
} from './chart-mix-common'
import { Datum } from '@antv/g2plot/esm/types/common'
import { useI18n } from '@/hooks/web/useI18n'
import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
import { Options } from '@antv/g2plot/esm'
const { t } = useI18n()
const DEFAULT_DATA = []
@ -74,8 +77,8 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
const isGroup = this.name === 'chart-mix-group' && chart.xAxisExt?.length > 0
const isStack = this.name === 'chart-mix-stack' && chart.extStack?.length > 0
const seriesField = isGroup ? 'category' : isStack ? 'category' : undefined
const seriesField2 = chart.extBubble?.length > 0 ? 'category' : undefined
const seriesField = 'category'
const seriesField2 = 'category'
const data1 = defaultTo(left[0]?.data, [])
const data2 = map(defaultTo(right[0]?.data, []), d => {
@ -85,29 +88,6 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
}
})
// custom color
const customAttr = parseJson(chart.customAttr)
let color = customAttr.basicStyle.colors
const colorSize = color.length
color = color.map(ele => {
const tmp = hexColorToRGBA(ele, customAttr.basicStyle.alpha)
if (customAttr.basicStyle.gradient) {
return setGradientColor(tmp, true, 270)
} else {
return tmp
}
})
const color2StartNum = defaultTo(left[0]?.categories?.length, 1)
const color2StartIndex = color2StartNum % colorSize
const color2 =
color2StartIndex === 0
? cloneDeep(color)
: union(slice(color, color2StartIndex), slice(color, 0, color2StartIndex))
// options
const initOptions: DualAxesOptions = {
data: [data1, data2],
@ -117,15 +97,14 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
geometryOptions: [
{
geometry: data1Type,
color: isGroup || isStack ? color : color[0],
color: [],
isGroup: isGroup,
isStack: isStack,
seriesField: seriesField
},
{
geometry: data2Type,
color: seriesField2 ? color2 : color2[0],
color: [],
seriesField: seriesField2
}
],
@ -295,12 +274,108 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
}
protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
const basicStyle = parseJson(chart.customAttr).basicStyle
const color = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha))
return {
...options,
color
const tempOption = {
...options
}
const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle
//左轴
const color = basicStyle.colors.map(ele => {
const tmp = hexColorToRGBA(ele, basicStyle.alpha)
if (basicStyle.gradient) {
return setGradientColor(tmp, true, 270)
} else {
return tmp
}
})
tempOption.geometryOptions[0].color = color
return tempOption
}
protected configSubCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
const tempOption = {
...options
}
const basicStyle = defaultsDeep(
parseJson(chart.customAttr).basicStyle as MixChartBasicStyle,
cloneDeep(CHART_MIX_DEFAULT_BASIC_STYLE)
)
//右轴
const { subSeriesColor } = basicStyle
if (subSeriesColor?.length) {
const { yAxisExt, extBubble } = chart
const seriesMap = subSeriesColor.reduce((p, n) => {
p[n.id] = n
return p
}, {})
const { data } = options as unknown as Options
if (extBubble?.length) {
const seriesSet = new Set()
data[1]?.forEach(d => d.category !== null && seriesSet.add(d.category))
const tmp = [...seriesSet]
tmp.forEach((c, i) => {
const curAxisColor = seriesMap[c as string]
if (curAxisColor) {
if (i + 1 > basicStyle.subColors.length) {
basicStyle.subColors.push(curAxisColor.color)
} else {
basicStyle.subColors[i] = curAxisColor.color
}
}
})
} else {
yAxisExt?.forEach((axis, index) => {
const curAxisColor = seriesMap[axis.id]
if (curAxisColor) {
if (index + 1 > basicStyle.subColors.length) {
basicStyle.subColors.push(curAxisColor.color)
} else {
basicStyle.subColors[index] = curAxisColor.color
}
}
})
}
}
const subColor = basicStyle.subColors.map(c => {
const cc = hexColorToRGBA(c, basicStyle.subAlpha)
return cc
})
tempOption.geometryOptions[1].color = subColor
return tempOption
}
public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
const result: ChartBasicStyle['seriesColor'] = []
const seriesSet = new Set<string>()
const colors = chart.customAttr.basicStyle.subColors ?? chart.customAttr.basicStyle.colors
const { yAxisExt, extBubble } = chart
if (extBubble?.length) {
data?.forEach(d => {
if (d.value === null || d.category === null || seriesSet.has(d.category)) {
return
}
seriesSet.add(d.category)
result.push({
id: d.category,
name: d.category,
color: colors[(seriesSet.size - 1) % colors.length]
})
})
} else {
yAxisExt?.forEach(axis => {
if (seriesSet.has(axis.id)) {
return
}
seriesSet.add(axis.id)
result.push({
id: axis.id,
name: axis.chartShowName ?? axis.name,
color: colors[(seriesSet.size - 1) % colors.length]
})
})
}
return result
}
protected configYAxis(chart: Chart, options: DualAxesOptions): DualAxesOptions {
@ -473,6 +548,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
this.configTooltip,
this.configBasicStyle,
this.configCustomColors,
this.configSubCustomColors,
this.configLegend,
this.configXAxis,
this.configYAxis,
@ -489,6 +565,18 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
export class GroupColumnLineMix extends ColumnLineMix {
axis: AxisType[] = [...this['axis'], 'xAxisExt']
propertyInner = {
...CHART_MIX_EDITOR_PROPERTY_INNER,
'dual-basic-style-selector': [
...CHART_MIX_EDITOR_PROPERTY_INNER['dual-basic-style-selector'],
'seriesColor'
],
'label-selector': ['vPosition', 'seriesLabelFormatter'],
'tooltip-selector': [
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
'seriesTooltipFormatter'
]
}
axisConfig = {
...this['axisConfig'],
yAxis: {
@ -497,12 +585,113 @@ export class GroupColumnLineMix extends ColumnLineMix {
type: 'q'
}
}
protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
const tempOption = {
...options
}
const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle
const { seriesColor } = basicStyle
if (seriesColor?.length) {
const seriesMap = seriesColor.reduce((p, n) => {
p[n.id] = n
return p
}, {})
const { yAxis, xAxisExt } = chart
const { data } = options as unknown as Options
if (xAxisExt?.length) {
const seriesSet = new Set()
data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category))
const tmp = [...seriesSet]
tmp.forEach((c, i) => {
const curAxisColor = seriesMap[c as string]
if (curAxisColor) {
if (i + 1 > basicStyle.colors.length) {
basicStyle.colors.push(curAxisColor.color)
} else {
basicStyle.colors[i] = curAxisColor.color
}
}
})
} else {
yAxis?.forEach((axis, index) => {
const curAxisColor = seriesMap[axis.id]
if (curAxisColor) {
if (index + 1 > basicStyle.colors.length) {
basicStyle.colors.push(curAxisColor.color)
} else {
basicStyle.colors[index] = curAxisColor.color
}
}
})
}
}
//左轴
const color = basicStyle.colors.map(ele => {
const tmp = hexColorToRGBA(ele, basicStyle.alpha)
if (basicStyle.gradient) {
return setGradientColor(tmp, true, 270)
} else {
return tmp
}
})
tempOption.geometryOptions[0].color = color
return tempOption
}
public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
const result: ChartBasicStyle['seriesColor'] = []
const seriesSet = new Set<string>()
const colors = chart.customAttr.basicStyle.colors
const { yAxis, xAxisExt } = chart
if (xAxisExt?.length) {
data?.forEach(d => {
if (d.value === null || d.category === null || seriesSet.has(d.category)) {
return
}
seriesSet.add(d.category)
result.push({
id: d.category,
name: d.category,
color: colors[(seriesSet.size - 1) % colors.length]
})
})
} else {
yAxis?.forEach(axis => {
if (seriesSet.has(axis.id)) {
return
}
seriesSet.add(axis.id)
result.push({
id: axis.id,
name: axis.chartShowName ?? axis.name,
color: colors[(seriesSet.size - 1) % colors.length]
})
})
}
return result
}
constructor(name = 'chart-mix-group') {
super(name)
}
}
export class StackColumnLineMix extends ColumnLineMix {
axis: AxisType[] = [...this['axis'], 'extStack']
propertyInner = {
...CHART_MIX_EDITOR_PROPERTY_INNER,
'dual-basic-style-selector': [
...CHART_MIX_EDITOR_PROPERTY_INNER['dual-basic-style-selector'],
'seriesColor'
],
'label-selector': ['vPosition', 'seriesLabelFormatter'],
'tooltip-selector': [
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
'seriesTooltipFormatter'
]
}
axisConfig = {
...this['axisConfig'],
yAxis: {
@ -511,6 +700,95 @@ export class StackColumnLineMix extends ColumnLineMix {
type: 'q'
}
}
protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions {
const tempOption = {
...options
}
const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle
const { seriesColor } = basicStyle
if (seriesColor?.length) {
const seriesMap = seriesColor.reduce((p, n) => {
p[n.id] = n
return p
}, {})
const { yAxis, extStack } = chart
const { data } = options as unknown as Options
if (extStack?.length) {
const seriesSet = new Set()
data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category))
const tmp = [...seriesSet]
tmp.forEach((c, i) => {
const curAxisColor = seriesMap[c as string]
if (curAxisColor) {
if (i + 1 > basicStyle.colors.length) {
basicStyle.colors.push(curAxisColor.color)
} else {
basicStyle.colors[i] = curAxisColor.color
}
}
})
} else {
yAxis?.forEach((axis, index) => {
const curAxisColor = seriesMap[axis.id]
if (curAxisColor) {
if (index + 1 > basicStyle.colors.length) {
basicStyle.colors.push(curAxisColor.color)
} else {
basicStyle.colors[index] = curAxisColor.color
}
}
})
}
}
//左轴
const color = basicStyle.colors.map(ele => {
const tmp = hexColorToRGBA(ele, basicStyle.alpha)
if (basicStyle.gradient) {
return setGradientColor(tmp, true, 270)
} else {
return tmp
}
})
tempOption.geometryOptions[0].color = color
return tempOption
}
public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
const result: ChartBasicStyle['seriesColor'] = []
const seriesSet = new Set<string>()
const colors = chart.customAttr.basicStyle.colors
const { yAxis, extStack } = chart
if (extStack?.length) {
data?.forEach(d => {
if (d.value === null || d.category === null || seriesSet.has(d.category)) {
return
}
seriesSet.add(d.category)
result.push({
id: d.category,
name: d.category,
color: colors[(seriesSet.size - 1) % colors.length]
})
})
} else {
yAxis?.forEach(axis => {
if (seriesSet.has(axis.id)) {
return
}
seriesSet.add(axis.id)
result.push({
id: axis.id,
name: axis.chartShowName ?? axis.name,
color: colors[(seriesSet.size - 1) % colors.length]
})
})
}
return result
}
constructor(name = 'chart-mix-stack') {
super(name)
}

View File

@ -165,6 +165,10 @@ export abstract class G2PlotChartView<
return setupSeriesColor(chart, data)
}
public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
return undefined
}
/**
* 流式配置公共参数处理常用的配置后续如果有其他通用配置也可以放进来需要单独配置的属性在各个图表自行实现
* @param chart 数据库图表对象