Merge pull request #11321 from dataease/dev-v2

merge bug fix
This commit is contained in:
fit2cloudrd 2024-08-01 15:59:36 +08:00 committed by GitHub
commit abf94727e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 964 additions and 99 deletions

View File

@ -80,7 +80,7 @@ curl -sSL https://dataease.oss-cn-hangzhou.aliyuncs.com/quick_start_v2.sh | bash
- [MaxKB](https://github.com/1panel-dev/MaxKB/) - 基于 LLM 大语言模型的开源知识库问答系统
- [JumpServer](https://github.com/jumpserver/jumpserver/) - 广受欢迎的开源堡垒机
- [Halo](https://github.com/halo-dev/halo/) - 强大易用的开源建站工具
- [MeterSphere](https://github.com/metersphere/metersphere/) - 开源的测试管理和接口测试工具
- [MeterSphere](https://github.com/metersphere/metersphere/) - 新一代的开源持续测试工具
## License

View File

@ -576,12 +576,19 @@ public class DataVisualizationServer implements DataVisualizationApi {
// 模板市场记录
coreOptRecentManage.saveOpt(request.getResourceName(), OptConstants.OPT_RESOURCE_TYPE.TEMPLATE, OptConstants.OPT_TYPE.NEW);
}
if(StringUtils.isNotEmpty(appDataStr)){
VisualizationExport2AppVO appDataFormat = JsonUtil.parseObject(appDataStr,VisualizationExport2AppVO.class);
String dvInfo = appDataFormat.getVisualizationInfo();
VisualizationBaseInfoVO baseInfoVO = JsonUtil.parseObject(dvInfo,VisualizationBaseInfoVO.class);
Long sourceDvId = baseInfoVO.getId();
appDataStr = appDataStr.replaceAll(sourceDvId.toString(), newDvId.toString());
if(StringUtils.isNotEmpty(appDataStr) && appDataStr.length()>10){
try{
VisualizationExport2AppVO appDataFormat = JsonUtil.parseObject(appDataStr,VisualizationExport2AppVO.class);
String dvInfo = appDataFormat.getVisualizationInfo();
VisualizationBaseInfoVO baseInfoVO = JsonUtil.parseObject(dvInfo,VisualizationBaseInfoVO.class);
Long sourceDvId = baseInfoVO.getId();
appDataStr = appDataStr.replaceAll(sourceDvId.toString(), newDvId.toString());
}catch (Exception e){
LogUtil.error(e);
appDataStr = null;
}
}else{
appDataStr = null;
}
// 解析动态数据
Map<String, String> dynamicDataMap = JsonUtil.parseObject(dynamicData, Map.class);

View File

@ -117,12 +117,12 @@ onMounted(async () => {
plugin.value = xpack.default
} else if (!window._de_xpack_not_loaded) {
window._de_xpack_not_loaded = true
window['Vue'] = Vue
window['Axios'] = axios
window['Pinia'] = Pinia
window['vueRouter'] = router
window['MittAll'] = useEmitt().emitter.all
window['I18n'] = i18n
window['VueDe'] = Vue
window['AxiosDe'] = axios
window['PiniaDe'] = Pinia
window['vueRouterDe'] = router
window['MittAllDe'] = useEmitt().emitter.all
window['I18nDe'] = i18n
if (!window.tinymce) {
window.tinymce = tinymce
}

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

@ -56,7 +56,7 @@ export function download2AppTemplate(downloadType, canvasDom, name, attachParams
componentData: JSON.stringify(componentData.value),
dynamicData: JSON.stringify(canvasViewDataTemplate),
staticResource: JSON.stringify(staticResource || {}),
appData: JSON.stringify(attachParams || {})
appData: attachParams ? JSON.stringify(attachParams) : null
}
const blob = new Blob([JSON.stringify(templateInfo)], { type: '' })
if (downloadType === 'template') {

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

@ -527,12 +527,15 @@ if (!chart.value.customStyle.component.hasOwnProperty('labelShow')) {
&.dark {
color: #a6a6a6;
&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
&.active {
color: var(--ed-color-primary);
background-color: var(--ed-color-primary-1a, rgba(51, 112, 255, 0.1));
}
&:hover {
background-color: rgba(255, 255, 255, 0.1);
&:hover {
background-color: #3370ff33;
}
}
}

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

@ -4,7 +4,7 @@ import { isEmpty } from 'lodash-es'
export const clearExtremum = chart => {
// 清除图表标注
const pointElement = document.getElementById('point_' + chart.id)
const pointElement = document.getElementById(chartPointParentId(chart))
if (pointElement) {
pointElement.remove()
pointElement.parentNode?.removeChild(pointElement)
@ -51,13 +51,13 @@ const getRgbaColorLastRgba = (rgbaString: string) => {
return lastRGBA
}
function createExtremumDiv(id, value, formatterCfg, chartId) {
function createExtremumDiv(id, value, formatterCfg, chart) {
// 空值不处理
if (!value && value != 0) {
return
}
// 装标注的div
const parentElement = document.getElementById('point_' + chartId)
const parentElement = document.getElementById(chartPointParentId(chart))
if (parentElement) {
// 标注div
const element = document.getElementById(id)
@ -103,8 +103,16 @@ const noChildrenFieldChart = chart => {
return ['area', 'bar'].includes(chart.type)
}
const chartContainerId = chart => {
return chart.container + '_'
}
const chartPointParentId = chart => {
return chart.container + '_point_' + chart.id + '_'
}
const overlap = chart => {
const container = document.getElementById('point_' + chart.id)
const container = document.getElementById(chartPointParentId(chart))
const children = Array.from(container.getElementsByClassName('child'))
function getOverlapArea(rect1, rect2) {
@ -145,7 +153,7 @@ export const extremumEvt = (newChart, chart, _options, container) => {
chart.container = container
const { label: labelAttr } = parseJson(chart.customAttr)
const { yAxis } = parseJson(chart)
newChart.on('beforerender', ev => {
newChart.once('beforerender', ev => {
ev.view.on('beforepaint', () => {
newChart.chart.geometries[0]?.beforeMappingData.forEach(i => {
i.forEach(item => {
@ -184,7 +192,7 @@ export const extremumEvt = (newChart, chart, _options, container) => {
.getController('legend')
.components[0].component.cfg.items.filter(l => !l.unchecked)
if (legendShowSize.length === 0) {
const allElement = document.getElementById('point_' + chart.id)
const allElement = document.getElementById(chartPointParentId(chart))
if (allElement && allElement.childNodes) {
allElement.childNodes.forEach(c => {
c.style.display = 'none'
@ -216,12 +224,11 @@ export const createExtremumPoint = (chart, ev) => {
const pointSize = basicStyle.lineSymbolSize
const { yAxis } = parseJson(chart)
clearExtremum(chart)
const parentKey = 'point_' + chart.id
// 创建标注父元素
const divParentElement = document.getElementById(parentKey)
const divParentElement = document.getElementById(chartPointParentId(chart))
if (!divParentElement) {
const divParent = document.createElement('div')
divParent.id = parentKey
divParent.id = chartPointParentId(chart)
divParent.style.position = 'fixed'
divParent.style.zIndex = '1'
// 将父标注加入到图表中
@ -267,12 +274,17 @@ export const createExtremumPoint = (chart, ev) => {
return
}
const maxKey =
parentKey +
'point_' +
chartContainerId(chart) +
chartPointParentId(chart) +
pointObj._origin.category +
'-' +
'_' +
(maxItem ? maxItem._origin.value : minItem._origin.value)
const minKey = parentKey + 'point_' + pointObj._origin.category + '-' + minItem._origin.value
const minKey =
chartContainerId(chart) +
chartPointParentId(chart) +
pointObj._origin.category +
'_' +
minItem._origin.value
// 最值标注
if (showExtremum && labelAttr.show) {
if (maxItem) {
@ -280,18 +292,22 @@ export const createExtremumPoint = (chart, ev) => {
maxKey,
maxItem._origin.value,
attr ? attr.formatterCfg : labelAttr.labelFormatter,
chart.id
chart
)
}
createExtremumDiv(
minKey,
minItem._origin.value,
attr ? attr.formatterCfg : labelAttr.labelFormatter,
chart.id
chart
)
pointObjList.forEach(point => {
const pointElement = document.getElementById(
parentKey + 'point_' + point._origin.category + '-' + point._origin.value
chartContainerId(chart) +
chartPointParentId(chart) +
point._origin.category +
'_' +
point._origin.value
)
if (pointElement && point._origin.EXTREME) {
pointElement.style.position = 'absolute'

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 数据库图表对象

View File

@ -40,7 +40,7 @@
>{{ t('visualization.apply_this_template') }}</el-button
>
<el-divider class="custom-divider-line" direction="vertical" />
<el-icon class="custom-market-icon hover-icon" @click="close"><Close /></el-icon>
<el-icon class="custom-market-icon hover-icon_custom" @click="close"><Close /></el-icon>
</el-row>
</el-row>
<el-row class="template-area">
@ -91,7 +91,7 @@
</el-select>
<template v-if="['branchCreate', 'create'].includes(state.curPosition)">
<el-divider class="custom-divider-line" direction="vertical" />
<el-icon class="custom-market-icon hover-icon" @click="close"><Close /></el-icon>
<el-icon class="custom-market-icon hover-icon_custom" @click="close"><Close /></el-icon>
</template>
</el-row>
</el-row>
@ -697,13 +697,32 @@ defineExpose({
.custom-divider-line {
height: 16px;
margin-top: 6px;
margin: 8px 14px 0 16px !important;
}
.custom-market-icon {
font-size: 20px;
margin-top: 4px;
height: 24px !important;
width: 24px !important;
cursor: pointer;
&.hover-icon_custom {
border-radius: 4px;
color: #646a73;
&[aria-expanded='true'] {
background: rgba(31, 35, 41, 0.1);
}
&:hover {
background: rgba(31, 35, 41, 0.1);
}
&:active {
background: rgba(31, 35, 41, 0.2);
}
}
}
.custom-back-icon {

@ -1 +1 @@
Subproject commit 5dfbeaaf9c02463f0fb7b9589ae78bd09ab88fc4
Subproject commit b177d56558c58c3dc89abb58a93bd722b0ea67ca

View File

@ -22,4 +22,6 @@ public class XpackLdapVO implements Serializable {
private String mapping;
private boolean enable;
}