更新前端src/views(chart和template)目录文件
This commit is contained in:
parent
1357172783
commit
f2582cb0d0
@ -29,6 +29,7 @@ const DashboardPanel = defineAsyncComponent(
|
|||||||
() => import('@/views/dashboard/DashboardPreviewShow.vue')
|
() => import('@/views/dashboard/DashboardPreviewShow.vue')
|
||||||
)
|
)
|
||||||
const Copilot = defineAsyncComponent(() => import('@/views/copilot/index.vue'))
|
const Copilot = defineAsyncComponent(() => import('@/views/copilot/index.vue'))
|
||||||
|
const TemplateManage = defineAsyncComponent(() => import('@/views/template/indexInject.vue'))
|
||||||
|
|
||||||
const AsyncXpackComponent = defineAsyncComponent(() => import('@/components/plugin/src/index.vue'))
|
const AsyncXpackComponent = defineAsyncComponent(() => import('@/components/plugin/src/index.vue'))
|
||||||
|
|
||||||
@ -42,7 +43,8 @@ const componentMap = {
|
|||||||
Datasource,
|
Datasource,
|
||||||
ScreenPanel,
|
ScreenPanel,
|
||||||
DashboardPanel,
|
DashboardPanel,
|
||||||
Copilot
|
Copilot,
|
||||||
|
TemplateManage
|
||||||
}
|
}
|
||||||
const iframeStyle = ref(null)
|
const iframeStyle = ref(null)
|
||||||
const setStyle = debounce(() => {
|
const setStyle = debounce(() => {
|
||||||
|
@ -127,19 +127,19 @@ const groupActiveChange = category => {
|
|||||||
.chart-light {
|
.chart-light {
|
||||||
color: #646a73 !important;
|
color: #646a73 !important;
|
||||||
:deep(.group-right) {
|
:deep(.group-right) {
|
||||||
border-left: 1px solid @side-outline-border-color-light;
|
border-left: 1px solid @side-outline-border-color-light!important;
|
||||||
}
|
}
|
||||||
:deep(.item-top) {
|
:deep(.item-top) {
|
||||||
background-color: #f5f6f7;
|
background-color: #f5f6f7 !important;
|
||||||
}
|
}
|
||||||
:deep(.ul-custom) {
|
:deep(.ul-custom) {
|
||||||
color: @chart-change-font-color-light!important;
|
color: @chart-change-font-color-light!important;
|
||||||
}
|
}
|
||||||
:deep(.item-bottom) {
|
:deep(.item-bottom) {
|
||||||
color: @chart-change-font-color-light;
|
color: @chart-change-font-color-light!important;
|
||||||
}
|
}
|
||||||
:deep(.item-top-icon) {
|
:deep(.item-top-icon) {
|
||||||
color: @chart-change-font-color-light;
|
color: @chart-change-font-color-light!important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.group {
|
.group {
|
||||||
|
@ -1,45 +1,98 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import dvUpArrow from '@/assets/svg/dv-up-arrow.svg'
|
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
defineProps({
|
||||||
|
themes: {
|
||||||
|
type: String,
|
||||||
|
default: 'light'
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="view-panel-Mask">
|
<div class="view-panel-mask-left"></div>
|
||||||
<Icon class-name="item-icon" name="dv-up-arrow"><dvUpArrow class="svg-icon item-icon" /></Icon>
|
<div class="view-panel-mask">
|
||||||
<div>
|
<el-popover
|
||||||
<el-button style="opacity: 1 !important" type="warning" size="mini" round>
|
:visible="true"
|
||||||
<span style="font-weight: bold; opacity: 1">{{
|
placement="bottom"
|
||||||
t('visualization.template_view_tips')
|
popper-class="template-popper-tips"
|
||||||
}}</span>
|
:width="256"
|
||||||
</el-button>
|
show-arrow
|
||||||
|
>
|
||||||
|
<div class="template-popper-tips-content">
|
||||||
|
<p class="constant">{{ t('visualization.template_view_tips') }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
<template #reference>
|
||||||
|
<div
|
||||||
|
class="view-panel-mask-inner"
|
||||||
|
:class="{ 'view-panel-mask-inner-dark': themes === 'dark' }"
|
||||||
|
></div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.view-panel-Mask {
|
.view-panel-mask-left {
|
||||||
display: flex;
|
height: 100%;
|
||||||
height: calc(100vh - 148px);
|
width: 240px;
|
||||||
width: 100%;
|
|
||||||
background-color: rgba(92, 94, 97, 0.7);
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 85px;
|
top: 0;
|
||||||
left: 0px;
|
left: 0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: rgba(31, 35, 41);
|
||||||
|
opacity: 0.4;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.view-panel-mask {
|
||||||
|
height: 100%;
|
||||||
|
width: 178px;
|
||||||
|
background-color: rgba(31, 35, 41);
|
||||||
|
opacity: 0.4;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 240px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
display: flex;
|
pointer-events: none;
|
||||||
align-items: center;
|
}
|
||||||
justify-content: center;
|
.view-panel-mask-inner {
|
||||||
|
top: 51px;
|
||||||
|
left: 6px;
|
||||||
|
height: 34px;
|
||||||
|
width: 170px;
|
||||||
|
background: white;
|
||||||
|
position: relative;
|
||||||
|
pointer-events: none;
|
||||||
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-icon {
|
.view-panel-mask-inner-dark {
|
||||||
position: absolute;
|
background: rgba(31, 35, 41);
|
||||||
top: 10px;
|
}
|
||||||
left: 300px;
|
</style>
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
<style lang="less">
|
||||||
opacity: 1;
|
.template-popper-tips {
|
||||||
color: #ff8800;
|
z-index: 1000 !important;
|
||||||
|
padding: 24px !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: 0 !important;
|
||||||
|
background: var(--ed-color-primary) !important;
|
||||||
|
inset: 0 auto auto -5px !important;
|
||||||
|
.ed-popper__arrow::before {
|
||||||
|
border: 1px solid var(--ed-color-primary) !important;
|
||||||
|
background: var(--ed-color-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.template-popper-tips-content {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
.content {
|
||||||
|
font-family: var(--de-custom_font, 'PingFang');
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import dvAi from '@/assets/svg/dv-ai.svg'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
const visible = ref(true)
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<el-popover
|
||||||
|
:visible="visible"
|
||||||
|
placement="bottom"
|
||||||
|
popper-class="ai-popper-tips"
|
||||||
|
:width="288"
|
||||||
|
show-arrow
|
||||||
|
>
|
||||||
|
<div class="ai-popper-tips-content">
|
||||||
|
<p class="constant">
|
||||||
|
你好,我是 DataEase 智能客服<br />点击一下,开启高效解答模式~<br />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<template #reference>
|
||||||
|
<div class="ai-popper-tips-icon">
|
||||||
|
<el-icon style="margin: 2px" class="ai-icon">
|
||||||
|
<Icon name="dv-ai"><dvAi class="svg-icon" /></Icon>
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.ai-popper-tips {
|
||||||
|
z-index: 10001 !important;
|
||||||
|
padding: 24px !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border: 0px !important;
|
||||||
|
background: var(--ed-color-primary) !important;
|
||||||
|
.ed-popper__arrow::before {
|
||||||
|
border: 1px solid var(--ed-color-primary) !important;
|
||||||
|
background: var(--ed-color-primary) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ai-popper-tips-content {
|
||||||
|
color: rgba(255, 255, 255, 1);
|
||||||
|
.title {
|
||||||
|
font-family: var(--de-custom_font, 'PingFang');
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 28px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
font-family: var(--de-custom_font, 'PingFang');
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.bottom {
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: right;
|
||||||
|
button {
|
||||||
|
border: 0px !important;
|
||||||
|
border-color: #ffffff !important;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(51, 112, 255, 1) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-popper-tips-icon {
|
||||||
|
margin: 0 8px;
|
||||||
|
z-index: 10003;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #ffffff;
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -373,13 +373,13 @@ onMounted(() => {
|
|||||||
</el-tree>
|
</el-tree>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-main>
|
</el-main>
|
||||||
<!-- <el-footer v-if="!isDataEaseBi">
|
<el-footer v-if="!isDataEaseBi">
|
||||||
<div class="footer-container">
|
<div class="footer-container">
|
||||||
<el-button type="primary" :icon="Plus" link class="add-btn" @click="addDataset">
|
<el-button type="primary" :icon="Plus" link class="add-btn" @click="addDataset">
|
||||||
{{ newSource }}
|
{{ newSource }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-footer> -->
|
</el-footer>
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
@ -405,7 +405,6 @@ onMounted(() => {
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
:deep(.ed-form-item.is-error .ed-input__wrapper) {
|
:deep(.ed-form-item.is-error .ed-input__wrapper) {
|
||||||
box-shadow: none !important;
|
|
||||||
input {
|
input {
|
||||||
color: var(--ed-color-danger);
|
color: var(--ed-color-danger);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ const emit = defineEmits([
|
|||||||
|
|
||||||
const { item } = toRefs(props)
|
const { item } = toRefs(props)
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes || 'dark'
|
||||||
})
|
})
|
||||||
const showValueFormatter = computed<boolean>(() => {
|
const showValueFormatter = computed<boolean>(() => {
|
||||||
return (
|
return (
|
||||||
@ -192,17 +192,25 @@ const showCustomSort = item => {
|
|||||||
}
|
}
|
||||||
return !item.chartId && (item.deType === 0 || item.deType === 5)
|
return !item.chartId && (item.deType === 0 || item.deType === 5)
|
||||||
}
|
}
|
||||||
const showSort = () => {
|
|
||||||
|
const NOT_SUPPORT_SORT = ['word-cloud', 'stock-line', 'treemap', 'circle-packing']
|
||||||
|
const showSort = computed(() => {
|
||||||
const { type: chartType } = props.chart
|
const { type: chartType } = props.chart
|
||||||
const { type: propType } = props
|
const { type: propType } = props
|
||||||
const notShowSort = ['word-cloud', 'stock-line'].includes(chartType)
|
const notShowSort = NOT_SUPPORT_SORT.includes(chartType)
|
||||||
if (notShowSort || propType === 'extColor') {
|
if (notShowSort || propType === 'extColor') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const isChartMix = chartType.includes('chart-mix')
|
const isChartMix = chartType.includes('chart-mix')
|
||||||
const isDimensionType = ['dimension', 'dimensionStack', 'dimensionExt'].includes(propType)
|
const isDimensionType = ['dimension', 'dimensionStack', 'dimensionExt'].includes(propType)
|
||||||
return !isChartMix || isDimensionType
|
return !isChartMix || isDimensionType
|
||||||
|
})
|
||||||
|
const showSortPriority = computed(() => {
|
||||||
|
if (props.chart.type.includes('chart-mix')) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
return showSort.value
|
||||||
|
})
|
||||||
const toggleHide = () => {
|
const toggleHide = () => {
|
||||||
item.value.index = props.index
|
item.value.index = props.index
|
||||||
item.value.hide = !item.value.hide
|
item.value.hide = !item.value.hide
|
||||||
@ -212,6 +220,7 @@ const toggleHide = () => {
|
|||||||
const showHideIcon = computed(() => {
|
const showHideIcon = computed(() => {
|
||||||
return ['table-info', 'table-normal'].includes(props.chart.type) && item.value.hide
|
return ['table-info', 'table-normal'].includes(props.chart.type) && item.value.hide
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getItemTagType()
|
getItemTagType()
|
||||||
})
|
})
|
||||||
@ -226,17 +235,17 @@ onMounted(() => {
|
|||||||
:style="{ backgroundColor: tagType + '0a', border: '1px solid ' + tagType }"
|
:style="{ backgroundColor: tagType + '0a', border: '1px solid ' + tagType }"
|
||||||
>
|
>
|
||||||
<span v-if="type !== 'extColor'" style="display: flex; color: #646a73">
|
<span v-if="type !== 'extColor'" style="display: flex; color: #646a73">
|
||||||
<el-icon v-if="'asc' === item.sort && showSort()">
|
<el-icon v-if="'asc' === item.sort && showSort">
|
||||||
<Icon name="icon_sort-a-to-z_outlined"
|
<Icon name="icon_sort-a-to-z_outlined"
|
||||||
><icon_sortAToZ_outlined class="svg-icon"
|
><icon_sortAToZ_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-icon v-if="'desc' === item.sort && showSort()">
|
<el-icon v-if="'desc' === item.sort && showSort">
|
||||||
<Icon name="icon_sort-z-to-a_outlined"
|
<Icon name="icon_sort-z-to-a_outlined"
|
||||||
><icon_sortZToA_outlined class="svg-icon"
|
><icon_sortZToA_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-icon v-if="'custom_sort' === item.sort && showSort()">
|
<el-icon v-if="'custom_sort' === item.sort && showSort">
|
||||||
<Icon name="icon_sort_outlined"><icon_sort_outlined class="svg-icon" /></Icon>
|
<Icon name="icon_sort_outlined"><icon_sort_outlined class="svg-icon" /></Icon>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
@ -283,7 +292,7 @@ onMounted(() => {
|
|||||||
class="item-span-style"
|
class="item-span-style"
|
||||||
:class="{
|
:class="{
|
||||||
'hidden-status': showHideIcon,
|
'hidden-status': showHideIcon,
|
||||||
'sort-status': showSort() && item.sort !== 'none'
|
'sort-status': showSort && item.sort !== 'none'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<span class="item-name">{{ item.chartShowName ? item.chartShowName : item.name }}</span>
|
<span class="item-name">{{ item.chartShowName ? item.chartShowName : item.name }}</span>
|
||||||
@ -312,7 +321,7 @@ onMounted(() => {
|
|||||||
class="drop-style"
|
class="drop-style"
|
||||||
:class="themes === 'dark' ? 'dark-dimension-quota' : ''"
|
:class="themes === 'dark' ? 'dark-dimension-quota' : ''"
|
||||||
>
|
>
|
||||||
<el-dropdown-item @click.prevent v-if="showSort()">
|
<el-dropdown-item @click.prevent v-if="showSort">
|
||||||
<el-dropdown
|
<el-dropdown
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
popper-class="data-dropdown_popper_mr9"
|
popper-class="data-dropdown_popper_mr9"
|
||||||
@ -398,14 +407,14 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<!-- <el-dropdown-item
|
<el-dropdown-item
|
||||||
v-if="showSort()"
|
v-if="showSortPriority"
|
||||||
:command="beforeClickItem('sortPriority')"
|
:command="beforeClickItem('sortPriority')"
|
||||||
class="menu-item-padding"
|
class="menu-item-padding"
|
||||||
>
|
>
|
||||||
<el-icon />
|
<el-icon />
|
||||||
<span>{{ t('chart.sort_priority') }}</span>
|
<span>{{ t('chart.sort_priority') }}</span>
|
||||||
</el-dropdown-item> -->
|
</el-dropdown-item>
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
@click.prevent
|
@click.prevent
|
||||||
v-if="item.deType === 1"
|
v-if="item.deType === 1"
|
||||||
@ -531,6 +540,25 @@ onMounted(() => {
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</span>
|
</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
class="menu-item-padding"
|
||||||
|
:command="beforeDateStyle('y_M_d_H')"
|
||||||
|
:divided="
|
||||||
|
chart.type.includes('bar-range') && ['quota', 'quotaExt'].includes(type)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="sub-menu-content"
|
||||||
|
:class="'y_M_d_H' === item.dateStyle ? 'content-active' : ''"
|
||||||
|
>
|
||||||
|
{{ t('chart.y_M_d_H') }}
|
||||||
|
<el-icon class="sub-menu-content--icon">
|
||||||
|
<Icon name="icon_done_outlined" v-if="'y_M_d_H' === item.dateStyle"
|
||||||
|
><icon_done_outlined class="svg-icon"
|
||||||
|
/></Icon>
|
||||||
|
</el-icon>
|
||||||
|
</span>
|
||||||
|
</el-dropdown-item>
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
class="menu-item-padding"
|
class="menu-item-padding"
|
||||||
:command="beforeDateStyle('y_M_d_H_m')"
|
:command="beforeDateStyle('y_M_d_H_m')"
|
||||||
@ -817,9 +845,17 @@ span {
|
|||||||
background-color: rgba(31, 35, 41, 0.1);
|
background-color: rgba(31, 35, 41, 0.1);
|
||||||
}
|
}
|
||||||
&.dark-dimension-quota {
|
&.dark-dimension-quota {
|
||||||
|
background-color: #292929;
|
||||||
|
border: 1px solid #434343;
|
||||||
|
:deep(.ed-dropdown-menu__item--divided) {
|
||||||
|
border-color: #ebebeb26;
|
||||||
|
}
|
||||||
.inner-dropdown-menu {
|
.inner-dropdown-menu {
|
||||||
color: rgba(235, 235, 235, 1);
|
color: rgba(235, 235, 235, 1);
|
||||||
}
|
}
|
||||||
|
:deep(.ed-dropdown-menu__item:not(.is-disabled):hover) {
|
||||||
|
background-color: #ebebeb1a;
|
||||||
|
}
|
||||||
:deep(.ed-dropdown-menu__item) {
|
:deep(.ed-dropdown-menu__item) {
|
||||||
color: rgba(235, 235, 235, 1);
|
color: rgba(235, 235, 235, 1);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import icon_sort_outlined from '@/assets/svg/icon_sort_outlined.svg'
|
|||||||
import icon_right_outlined from '@/assets/svg/icon_right_outlined.svg'
|
import icon_right_outlined from '@/assets/svg/icon_right_outlined.svg'
|
||||||
import icon_done_outlined from '@/assets/svg/icon_done_outlined.svg'
|
import icon_done_outlined from '@/assets/svg/icon_done_outlined.svg'
|
||||||
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
|
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
|
||||||
import icon_sort_priority from '@/assets/svg/icon_sort_priority.svg'
|
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { onMounted, ref, toRefs, watch } from 'vue'
|
import { onMounted, ref, toRefs, watch } from 'vue'
|
||||||
import { getItemType } from '@/views/chart/components/editor/drag-item/utils'
|
import { getItemType } from '@/views/chart/components/editor/drag-item/utils'
|
||||||
@ -165,7 +164,7 @@ onMounted(() => {
|
|||||||
></Icon>
|
></Icon>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</span>
|
</span>
|
||||||
<el-tooltip :effect="themes === 'dark' ? 'ndark' : 'dark'" placement="top">
|
<el-tooltip :effect="themes || 'dark'" placement="top">
|
||||||
<template #content>
|
<template #content>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -450,9 +449,18 @@ span {
|
|||||||
background-color: rgba(31, 35, 41, 0.1);
|
background-color: rgba(31, 35, 41, 0.1);
|
||||||
}
|
}
|
||||||
&.dark-dimension-quota {
|
&.dark-dimension-quota {
|
||||||
|
background-color: #292929;
|
||||||
|
border: 1px solid #434343;
|
||||||
|
:deep(.ed-dropdown-menu__item--divided) {
|
||||||
|
border-color: #ebebeb26;
|
||||||
|
}
|
||||||
.inner-dropdown-menu {
|
.inner-dropdown-menu {
|
||||||
color: rgba(235, 235, 235, 1);
|
color: rgba(235, 235, 235, 1);
|
||||||
}
|
}
|
||||||
|
:deep(.ed-dropdown-menu__item:not(.is-disabled):hover) {
|
||||||
|
background-color: #ebebeb1a;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.ed-dropdown-menu__item) {
|
:deep(.ed-dropdown-menu__item) {
|
||||||
color: rgba(235, 235, 235, 1);
|
color: rgba(235, 235, 235, 1);
|
||||||
}
|
}
|
||||||
@ -531,6 +539,7 @@ span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.dark-dimension-quota {
|
.dark-dimension-quota {
|
||||||
|
background-color: #292929;
|
||||||
span {
|
span {
|
||||||
color: #ebebeb;
|
color: #ebebeb;
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ const emit = defineEmits([
|
|||||||
|
|
||||||
const { item, chart } = toRefs(props)
|
const { item, chart } = toRefs(props)
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes || 'dark'
|
||||||
})
|
})
|
||||||
watch(
|
watch(
|
||||||
[() => props.quotaData, () => props.item, () => props.chart.type],
|
[() => props.quotaData, () => props.item, () => props.chart.type],
|
||||||
@ -210,11 +210,6 @@ const beforeSort = type => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const switchChartType = param => {
|
|
||||||
item.value.chartType = param.type
|
|
||||||
emit('onQuotaItemChange', item.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const summary = param => {
|
const summary = param => {
|
||||||
item.value.summary = param.type
|
item.value.summary = param.type
|
||||||
emit('onQuotaItemChange', item.value)
|
emit('onQuotaItemChange', item.value)
|
||||||
@ -226,12 +221,6 @@ const beforeSummary = type => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const beforeSwitchType = type => {
|
|
||||||
return {
|
|
||||||
type: type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const showRename = () => {
|
const showRename = () => {
|
||||||
item.value.index = props.index
|
item.value.index = props.index
|
||||||
item.value.renameType = props.type
|
item.value.renameType = props.type
|
||||||
@ -315,14 +304,23 @@ const showHideIcon = computed(() => {
|
|||||||
return ['tale-info', 'table-normal'].includes(props.chart.type) && item.value.hide
|
return ['tale-info', 'table-normal'].includes(props.chart.type) && item.value.hide
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const NOT_SUPPORT_SORT = [
|
||||||
|
'circle-packing',
|
||||||
|
'indicator',
|
||||||
|
'liquid',
|
||||||
|
'gauge',
|
||||||
|
'word-cloud',
|
||||||
|
'stock-line',
|
||||||
|
'treemap'
|
||||||
|
]
|
||||||
|
|
||||||
const showSort = computed(() => {
|
const showSort = computed(() => {
|
||||||
return (
|
return (
|
||||||
props.type !== 'extLabel' &&
|
props.type !== 'extLabel' &&
|
||||||
props.type !== 'extTooltip' &&
|
props.type !== 'extTooltip' &&
|
||||||
props.type !== 'extBubble' &&
|
props.type !== 'extBubble' &&
|
||||||
!['chart-mix', 'indicator', 'liquid', 'gauge', 'word-cloud', 'stock-line'].includes(
|
!NOT_SUPPORT_SORT.includes(chart.value.type) &&
|
||||||
chart.value.type
|
!chart.value.type.includes('chart-mix')
|
||||||
)
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -613,7 +611,9 @@ onMounted(() => {
|
|||||||
<!--同比/环比等快速计算-->
|
<!--同比/环比等快速计算-->
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
@click.prevent
|
@click.prevent
|
||||||
v-if="chart.type !== 'table-info' && props.type !== 'extBubble'"
|
v-if="
|
||||||
|
!['table-info', 'bullet-graph'].includes(chart.type) && props.type !== 'extBubble'
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<el-dropdown
|
<el-dropdown
|
||||||
placement="right-start"
|
placement="right-start"
|
||||||
@ -661,6 +661,7 @@ onMounted(() => {
|
|||||||
class="menu-item-padding"
|
class="menu-item-padding"
|
||||||
:disabled="state.disableEditCompare"
|
:disabled="state.disableEditCompare"
|
||||||
:command="beforeQuickCalc('setting')"
|
:command="beforeQuickCalc('setting')"
|
||||||
|
v-if="!(chart.type.includes('chart-mix') && type === 'quotaExt')"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="sub-menu-content"
|
class="sub-menu-content"
|
||||||
@ -790,14 +791,14 @@ onMounted(() => {
|
|||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|
||||||
<!-- <el-dropdown-item
|
<el-dropdown-item
|
||||||
v-if="showSort"
|
v-if="showSort"
|
||||||
class="menu-item-padding"
|
class="menu-item-padding"
|
||||||
:command="beforeClickItem('sortPriority')"
|
:command="beforeClickItem('sortPriority')"
|
||||||
>
|
>
|
||||||
<el-icon />
|
<el-icon />
|
||||||
<span>{{ t('chart.sort_priority') }}</span>
|
<span>{{ t('chart.sort_priority') }}</span>
|
||||||
</el-dropdown-item> -->
|
</el-dropdown-item>
|
||||||
|
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
class="menu-item-padding"
|
class="menu-item-padding"
|
||||||
@ -998,6 +999,14 @@ span {
|
|||||||
background-color: rgba(31, 35, 41, 0.1);
|
background-color: rgba(31, 35, 41, 0.1);
|
||||||
}
|
}
|
||||||
&.dark-dimension-quota {
|
&.dark-dimension-quota {
|
||||||
|
background-color: #292929;
|
||||||
|
border: 1px solid #434343;
|
||||||
|
:deep(.ed-dropdown-menu__item--divided) {
|
||||||
|
border-color: #ebebeb26;
|
||||||
|
}
|
||||||
|
:deep(.ed-dropdown-menu__item:not(.is-disabled):hover) {
|
||||||
|
background-color: #ebebeb1a;
|
||||||
|
}
|
||||||
.inner-dropdown-menu {
|
.inner-dropdown-menu {
|
||||||
color: rgba(235, 235, 235, 1);
|
color: rgba(235, 235, 235, 1);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,11 @@ const props = defineProps({
|
|||||||
fieldType: {
|
fieldType: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
originSortList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
required: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -54,6 +59,17 @@ const init = () => {
|
|||||||
reqMethod(param)
|
reqMethod(param)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const strArr = response.data
|
const strArr = response.data
|
||||||
|
if (props.originSortList?.length) {
|
||||||
|
const tmp = []
|
||||||
|
props.originSortList.forEach(ele => {
|
||||||
|
const index = strArr.findIndex(item => item === ele)
|
||||||
|
if (index !== -1) {
|
||||||
|
tmp.push(strArr[index])
|
||||||
|
strArr.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
strArr.unshift(...tmp)
|
||||||
|
}
|
||||||
state.sortList = strArr.map(ele => {
|
state.sortList = strArr.map(ele => {
|
||||||
return transStr2Obj(ele)
|
return transStr2Obj(ele)
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { reactive, toRefs } from 'vue'
|
import { reactive, toRefs } from 'vue'
|
||||||
import { formatterType, unitType, valueFormatter } from '@/views/chart/components/js/formatter'
|
import {
|
||||||
|
isEnLocal,
|
||||||
|
formatterType,
|
||||||
|
getUnitTypeList,
|
||||||
|
onChangeFormatCfgUnitLanguage,
|
||||||
|
valueFormatter,
|
||||||
|
initFormatCfgUnit
|
||||||
|
} from '@/views/chart/components/js/formatter'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -20,13 +27,19 @@ const { formatterItem } = toRefs(props)
|
|||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
typeList: formatterType,
|
typeList: formatterType,
|
||||||
unitList: unitType,
|
|
||||||
exampleResult: '20000000'
|
exampleResult: '20000000'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function changeUnitLanguage(cfg: BaseFormatter, lang) {
|
||||||
|
onChangeFormatCfgUnitLanguage(cfg, lang)
|
||||||
|
getExampleValue()
|
||||||
|
}
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
if (!formatterItem.value.formatterCfg) {
|
if (!formatterItem.value.formatterCfg) {
|
||||||
formatterItem.value.formatterCfg = formatterItem
|
formatterItem.value.formatterCfg = formatterItem
|
||||||
|
|
||||||
|
initFormatCfgUnit(formatterItem.value.formatterCfg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getExampleValue = () => {
|
const getExampleValue = () => {
|
||||||
@ -66,10 +79,22 @@ getExampleValue()
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item
|
<template v-if="formatterItem.formatterCfg.type !== 'percent'">
|
||||||
v-if="formatterItem.formatterCfg.type !== 'percent'"
|
<el-row :gutter="8">
|
||||||
:label="t('chart.value_formatter_unit')"
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item :label="t('chart.value_formatter_unit_language')">
|
||||||
|
<el-select
|
||||||
|
v-model="formatterItem.formatterCfg.unitLanguage"
|
||||||
|
:placeholder="t('chart.pls_select_field')"
|
||||||
|
@change="v => changeUnitLanguage(formatterItem.formatterCfg, v)"
|
||||||
>
|
>
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
|
<el-form-item :label="t('chart.value_formatter_unit')">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="formatterItem.formatterCfg.unit"
|
v-model="formatterItem.formatterCfg.unit"
|
||||||
:placeholder="t('chart.pls_select_field')"
|
:placeholder="t('chart.pls_select_field')"
|
||||||
@ -77,13 +102,16 @@ getExampleValue()
|
|||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in state.unitList"
|
v-for="item in getUnitTypeList(formatterItem.formatterCfg.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item :label="t('chart.value_formatter_suffix')">
|
<el-form-item :label="t('chart.value_formatter_suffix')">
|
||||||
<el-input
|
<el-input
|
||||||
|
@ -22,6 +22,7 @@ export function getItemType(dimensionData, quotaData, item) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
|
ele.id === item.id &&
|
||||||
ele.originName === item.originName &&
|
ele.originName === item.originName &&
|
||||||
ele.deType === item.deType &&
|
ele.deType === item.deType &&
|
||||||
ele.groupType === item.groupType
|
ele.groupType === item.groupType
|
||||||
|
@ -36,7 +36,7 @@ import { Icon } from 'vant'
|
|||||||
import CommonEvent from '@/custom-component/common/CommonEvent.vue'
|
import CommonEvent from '@/custom-component/common/CommonEvent.vue'
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
|
|
||||||
const { nowPanelTrackInfo, nowPanelJumpInfo, dvInfo, componentData, curComponent, batchOptStatus } =
|
const { nowPanelTrackInfo, nowPanelJumpInfo, dvInfo, curComponent, batchOptStatus } =
|
||||||
storeToRefs(dvMainStore)
|
storeToRefs(dvMainStore)
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@ -223,7 +223,7 @@ const appStore = useAppStoreWithOut()
|
|||||||
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
||||||
|
|
||||||
const removeLinkageSenior = () => {
|
const removeLinkageSenior = () => {
|
||||||
removeLinkage({ dvId: dvInfo.value.id, sourceViewId: chart.value.id }).then(rsp => {
|
removeLinkage({ dvId: dvInfo.value.id, sourceViewId: chart.value.id }).then(() => {
|
||||||
// 刷新联动信息
|
// 刷新联动信息
|
||||||
getPanelAllLinkageInfo(dvInfo.value.id).then(rsp => {
|
getPanelAllLinkageInfo(dvInfo.value.id).then(rsp => {
|
||||||
dvMainStore.setNowPanelTrackInfo(rsp.data)
|
dvMainStore.setNowPanelTrackInfo(rsp.data)
|
||||||
@ -232,7 +232,7 @@ const removeLinkageSenior = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const removeJumpSenior = () => {
|
const removeJumpSenior = () => {
|
||||||
removeJumpSet({ sourceDvId: dvInfo.value.id, sourceViewId: chart.value.id }).then(rspCur => {
|
removeJumpSet({ sourceDvId: dvInfo.value.id, sourceViewId: chart.value.id }).then(() => {
|
||||||
// 刷新跳转信息
|
// 刷新跳转信息
|
||||||
queryVisualizationJumpInfo(dvInfo.value.id).then(rsp => {
|
queryVisualizationJumpInfo(dvInfo.value.id).then(rsp => {
|
||||||
dvMainStore.setNowPanelJumpInfo(rsp.data)
|
dvMainStore.setNowPanelJumpInfo(rsp.data)
|
||||||
@ -334,6 +334,7 @@ const removeJumpSenior = () => {
|
|||||||
:chart="chart"
|
:chart="chart"
|
||||||
:themes="themes"
|
:themes="themes"
|
||||||
:is-screen="dvInfo.type === 'dataV'"
|
:is-screen="dvInfo.type === 'dataV'"
|
||||||
|
:resource-table="'snapshot'"
|
||||||
jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9TZW5pb3JIYW5kbGVy"
|
jsname="L2NvbXBvbmVudC90aHJlc2hvbGQtd2FybmluZy9TZW5pb3JIYW5kbGVy"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -524,6 +525,9 @@ span {
|
|||||||
:deep(.ed-form-item__label) {
|
:deep(.ed-form-item__label) {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
:deep(.style-collapse) {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-dark {
|
.label-dark {
|
||||||
@ -576,3 +580,11 @@ span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.senior-dark {
|
||||||
|
.label-dark {
|
||||||
|
color: #a6a6a6 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -224,7 +224,7 @@ onMounted(() => {
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="assist-line-cfg-header">
|
<div class="assist-line-cfg-header">
|
||||||
<span class="ed-dialog__title">{{ t('chart.assist_line') }}</span>
|
<span class="ed-dialog__title">{{ t('chart.assist_line') }}</span>
|
||||||
<el-tooltip class="item" effect="ndark" placement="top">
|
<el-tooltip class="item" effect="light" placement="top">
|
||||||
<template #content>
|
<template #content>
|
||||||
<span> {{ t('chart.assist_line_tip') }}</span>
|
<span> {{ t('chart.assist_line_tip') }}</span>
|
||||||
</template>
|
</template>
|
||||||
@ -392,12 +392,4 @@ span {
|
|||||||
color: #a6a6a6;
|
color: #a6a6a6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ed-button{
|
|
||||||
color: #F2F4F5;
|
|
||||||
background-color: #212121;
|
|
||||||
border: 1px solid #434343;
|
|
||||||
}
|
|
||||||
.ed-button--primary{
|
|
||||||
background-color:#0089FF;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -799,7 +799,7 @@ init()
|
|||||||
<span
|
<span
|
||||||
class="set-text-info"
|
class="set-text-info"
|
||||||
:class="{ 'set-text-info-dark': themes === 'dark' }"
|
:class="{ 'set-text-info-dark': themes === 'dark' }"
|
||||||
v-if="state.thresholdForm?.tableThreshold?.length > 0"
|
v-if="state.thresholdForm?.lineThresholdArr?.length > 0"
|
||||||
>
|
>
|
||||||
$t('visualization.already_setting')
|
$t('visualization.already_setting')
|
||||||
</span>
|
</span>
|
||||||
@ -1347,13 +1347,4 @@ span {
|
|||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
}
|
}
|
||||||
.dialog-footer .ed-button{
|
|
||||||
color: #F2F4F5;
|
|
||||||
background-color: #212121;
|
|
||||||
border: 1px solid #434343;
|
|
||||||
}
|
|
||||||
.dialog-footer .ed-button--primary{
|
|
||||||
background-color:#0089FF;
|
|
||||||
border: 1px solid #0089FF;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -269,6 +269,7 @@ onMounted(() => {
|
|||||||
<el-option key="avg" value="avg" label="平均值" />
|
<el-option key="avg" value="avg" label="平均值" />
|
||||||
<el-option key="max" value="max" :label="t('chart.max')" />
|
<el-option key="max" value="max" :label="t('chart.max')" />
|
||||||
<el-option key="min" value="min" :label="t('chart.min')" />
|
<el-option key="min" value="min" :label="t('chart.min')" />
|
||||||
|
<el-option key="last_item" value="last_item" :label="t('chart.last_item')" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="useQuotaExt ? 2 : 3">
|
<el-col :span="useQuotaExt ? 2 : 3">
|
||||||
@ -298,10 +299,10 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="2" style="text-align: center">
|
<el-col :span="2">
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
is-custom
|
is-custom
|
||||||
size="large"
|
:trigger-width="60"
|
||||||
v-model="item.color"
|
v-model="item.color"
|
||||||
class="color-picker-style"
|
class="color-picker-style"
|
||||||
:predefine="state.predefineColors"
|
:predefine="state.predefineColors"
|
||||||
@ -377,45 +378,4 @@ span {
|
|||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
:deep(.ed-input__wrapper){
|
|
||||||
background-color: #292929 ;
|
|
||||||
box-shadow: none;
|
|
||||||
border: 1px solid #636363;
|
|
||||||
}
|
|
||||||
:deep(.ed-input__inner){
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
:deep(.ed-input-number__decrease){
|
|
||||||
background-color: #434343 !important;
|
|
||||||
color:#ffffff;
|
|
||||||
}
|
|
||||||
:deep(.ed-input-number__increase){
|
|
||||||
background-color: #434343 !important;
|
|
||||||
color:#ffffff !important;
|
|
||||||
}
|
|
||||||
:deep(.ed-input-number.is-controls-right .ed-input-number__increase){
|
|
||||||
border-bottom: 1px solid #434343 !important;
|
|
||||||
border-left: 1px solid #5f5f5f !important;
|
|
||||||
}
|
|
||||||
:deep(.ed-input-number.is-controls-right .ed-input-number__decrease){
|
|
||||||
border-left: 1px solid #5f5f5f !important;
|
|
||||||
}
|
|
||||||
:deep(.ed-select-dropdown__item){
|
|
||||||
color: #ffffff !important;
|
|
||||||
}
|
|
||||||
:deep(.ed-select-dropdown__item.hover, .ed-select-dropdown__item:hover){
|
|
||||||
background: rgb(61,61,61) !important;
|
|
||||||
}
|
|
||||||
.ed-select-dropdown__item{
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
.ed-select-dropdown__item.hover, .ed-select-dropdown__item:hover{
|
|
||||||
background: rgb(61,61,61);
|
|
||||||
}
|
|
||||||
.ed-select-dropdown__item.selected{
|
|
||||||
color: #0089ff;
|
|
||||||
}
|
|
||||||
:deep(.ed-color-picker__trigger){
|
|
||||||
border: 1px solid #5f5f5f ;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -269,7 +269,11 @@ init()
|
|||||||
>
|
>
|
||||||
<el-row style="margin-top: 6px; align-items: center; justify-content: space-between">
|
<el-row style="margin-top: 6px; align-items: center; justify-content: space-between">
|
||||||
<el-form-item class="form-item">
|
<el-form-item class="form-item">
|
||||||
<el-select v-model="fieldItem.fieldId" @change="addField(fieldItem)">
|
<el-select
|
||||||
|
style="width: 181px"
|
||||||
|
v-model="fieldItem.fieldId"
|
||||||
|
@change="addField(fieldItem)"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
class="series-select-option"
|
class="series-select-option"
|
||||||
v-for="fieldOption in state.fields"
|
v-for="fieldOption in state.fields"
|
||||||
@ -424,7 +428,7 @@ init()
|
|||||||
>
|
>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
is-custom
|
is-custom
|
||||||
size="large"
|
:trigger-width="60"
|
||||||
v-model="item.color"
|
v-model="item.color"
|
||||||
show-alpha
|
show-alpha
|
||||||
class="color-picker-style"
|
class="color-picker-style"
|
||||||
@ -452,7 +456,7 @@ init()
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-button
|
<el-button
|
||||||
style="margin-top: 10px;"
|
style="margin-top: 10px"
|
||||||
class="circle-button"
|
class="circle-button"
|
||||||
type="primary"
|
type="primary"
|
||||||
text
|
text
|
||||||
|
@ -4,7 +4,6 @@ import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.s
|
|||||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||||
import { PropType, reactive } from 'vue'
|
import { PropType, reactive } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL } from '../../../util/chart'
|
|
||||||
import { fieldType } from '@/utils/attr'
|
import { fieldType } from '@/utils/attr'
|
||||||
import { iconFieldMap } from '@/components/icon-group/field-list'
|
import { iconFieldMap } from '@/components/icon-group/field-list'
|
||||||
import PictureItem from '@/custom-component/picture-group/PictureItem.vue'
|
import PictureItem from '@/custom-component/picture-group/PictureItem.vue'
|
||||||
@ -201,7 +200,6 @@ const valueOptions = [
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
const predefineColors = COLOR_PANEL
|
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
thresholdArr: [] as TableThreshold[],
|
thresholdArr: [] as TableThreshold[],
|
||||||
@ -303,7 +301,11 @@ init()
|
|||||||
>
|
>
|
||||||
<el-row style="margin-top: 6px; align-items: center; justify-content: space-between">
|
<el-row style="margin-top: 6px; align-items: center; justify-content: space-between">
|
||||||
<el-form-item class="form-item">
|
<el-form-item class="form-item">
|
||||||
<el-select v-model="fieldItem.fieldId" @change="addField(fieldItem)">
|
<el-select
|
||||||
|
style="width: 181px"
|
||||||
|
v-model="fieldItem.fieldId"
|
||||||
|
@change="addField(fieldItem)"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
class="series-select-option"
|
class="series-select-option"
|
||||||
v-for="fieldOption in state.fields"
|
v-for="fieldOption in state.fields"
|
||||||
@ -334,7 +336,7 @@ init()
|
|||||||
:style="{ float: 'right' }"
|
:style="{ float: 'right' }"
|
||||||
@click="removeThreshold(fieldIndex)"
|
@click="removeThreshold(fieldIndex)"
|
||||||
>
|
>
|
||||||
<el-icon size="20px" style="color: #979797">
|
<el-icon size="20px" style="color: #646a73">
|
||||||
<Icon name="icon_delete-trash_outlined"
|
<Icon name="icon_delete-trash_outlined"
|
||||||
><icon_deleteTrash_outlined class="svg-icon"
|
><icon_deleteTrash_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
@ -342,7 +344,7 @@ init()
|
|||||||
</el-button>
|
</el-button>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row :style="{ marginTop: '16px', borderTop: '1px solid #5f5f5f' }">
|
<el-row :style="{ marginTop: '16px', borderTop: '1px solid #d5d6d8' }">
|
||||||
<el-row
|
<el-row
|
||||||
v-for="(item, index) in fieldItem.conditions"
|
v-for="(item, index) in fieldItem.conditions"
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -437,6 +439,7 @@ init()
|
|||||||
<el-select
|
<el-select
|
||||||
v-model="item.url"
|
v-model="item.url"
|
||||||
@change="changeThreshold"
|
@change="changeThreshold"
|
||||||
|
style="width: 181px"
|
||||||
popper-class="picture-group-select"
|
popper-class="picture-group-select"
|
||||||
>
|
>
|
||||||
<template v-if="item.url" #prefix>
|
<template v-if="item.url" #prefix>
|
||||||
@ -464,7 +467,7 @@ init()
|
|||||||
text
|
text
|
||||||
@click="removeCondition(fieldItem, index)"
|
@click="removeCondition(fieldItem, index)"
|
||||||
>
|
>
|
||||||
<el-icon size="20px" style="color: #979797">
|
<el-icon size="20px" style="color: #646a73">
|
||||||
<Icon name="icon_delete-trash_outlined"
|
<Icon name="icon_delete-trash_outlined"
|
||||||
><icon_deleteTrash_outlined class="svg-icon"
|
><icon_deleteTrash_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
|
@ -25,7 +25,7 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(['onTableThresholdChange'])
|
const emit = defineEmits(['onTableThresholdChange'])
|
||||||
|
|
||||||
const thresholdCondition = {
|
const thresholdCondition = {
|
||||||
term: 'eq',
|
term: '',
|
||||||
field: '0',
|
field: '0',
|
||||||
value: '0',
|
value: '0',
|
||||||
color: '#ff0000ff',
|
color: '#ff0000ff',
|
||||||
@ -373,7 +373,7 @@ const changeConditionItemType = item => {
|
|||||||
item.dynamicMaxField.summary = 'value'
|
item.dynamicMaxField.summary = 'value'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getFieldOptions = fieldItem => {
|
const getFieldOptions = () => {
|
||||||
return fieldOptions
|
return fieldOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +397,11 @@ init()
|
|||||||
>
|
>
|
||||||
<el-row style="margin-top: 6px; align-items: center; justify-content: space-between">
|
<el-row style="margin-top: 6px; align-items: center; justify-content: space-between">
|
||||||
<el-form-item class="form-item">
|
<el-form-item class="form-item">
|
||||||
<el-select v-model="fieldItem.fieldId" @change="addField(fieldItem)">
|
<el-select
|
||||||
|
style="width: 181px"
|
||||||
|
v-model="fieldItem.fieldId"
|
||||||
|
@change="addField(fieldItem)"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
class="series-select-option"
|
class="series-select-option"
|
||||||
v-for="fieldOption in state.fields"
|
v-for="fieldOption in state.fields"
|
||||||
@ -428,7 +432,7 @@ init()
|
|||||||
:style="{ float: 'right' }"
|
:style="{ float: 'right' }"
|
||||||
@click="removeThreshold(fieldIndex)"
|
@click="removeThreshold(fieldIndex)"
|
||||||
>
|
>
|
||||||
<el-icon size="20px" style="color: #979797">
|
<el-icon size="20px" style="color: #646a73">
|
||||||
<Icon name="icon_delete-trash_outlined"
|
<Icon name="icon_delete-trash_outlined"
|
||||||
><icon_deleteTrash_outlined class="svg-icon"
|
><icon_deleteTrash_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
@ -436,7 +440,7 @@ init()
|
|||||||
</el-button>
|
</el-button>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-row :style="{ marginTop: '16px', borderTop: '1px solid #5f5f5f !important' }">
|
<el-row :style="{ marginTop: '16px', borderTop: '1px solid #d5d6d8' }">
|
||||||
<el-row
|
<el-row
|
||||||
v-for="(item, index) in fieldItem.conditions"
|
v-for="(item, index) in fieldItem.conditions"
|
||||||
:key="index"
|
:key="index"
|
||||||
@ -735,9 +739,9 @@ init()
|
|||||||
<el-form-item class="form-item" :label="t('chart.textColor')">
|
<el-form-item class="form-item" :label="t('chart.textColor')">
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
is-custom
|
is-custom
|
||||||
size="large"
|
|
||||||
v-model="item.color"
|
v-model="item.color"
|
||||||
show-alpha
|
show-alpha
|
||||||
|
:trigger-width="68"
|
||||||
class="color-picker-style"
|
class="color-picker-style"
|
||||||
:predefine="predefineColors"
|
:predefine="predefineColors"
|
||||||
@change="changeThreshold"
|
@change="changeThreshold"
|
||||||
@ -748,8 +752,9 @@ init()
|
|||||||
<el-form-item class="form-item" :label="t('chart.backgroundColor')">
|
<el-form-item class="form-item" :label="t('chart.backgroundColor')">
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
is-custom
|
is-custom
|
||||||
size="large"
|
size="default"
|
||||||
v-model="item.backgroundColor"
|
v-model="item.backgroundColor"
|
||||||
|
:trigger-width="68"
|
||||||
show-alpha
|
show-alpha
|
||||||
class="color-picker-style"
|
class="color-picker-style"
|
||||||
:predefine="predefineColors"
|
:predefine="predefineColors"
|
||||||
@ -764,7 +769,7 @@ init()
|
|||||||
text
|
text
|
||||||
@click="removeCondition(fieldItem, index)"
|
@click="removeCondition(fieldItem, index)"
|
||||||
>
|
>
|
||||||
<el-icon size="20px" style="color: #979797">
|
<el-icon size="20px" style="color: #646a73">
|
||||||
<Icon name="icon_delete-trash_outlined"
|
<Icon name="icon_delete-trash_outlined"
|
||||||
><icon_deleteTrash_outlined class="svg-icon"
|
><icon_deleteTrash_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
@ -856,18 +861,12 @@ span {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-picker-style {
|
:deep(.color-picker-style) {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 1003;
|
z-index: 1003;
|
||||||
width: 28px;
|
height: 32px;
|
||||||
height: 28px;
|
line-height: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-picker-style :deep(.el-color-picker__trigger) {
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-title {
|
.color-title {
|
||||||
color: #646a73;
|
color: #646a73;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -166,11 +166,11 @@ init()
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-space>
|
</el-space>
|
||||||
</el-col>
|
</el-col>
|
||||||
<div style="display: flex; align-items: center; justify-content: center; margin-left: 15px">
|
<div style="display: flex; align-items: center; justify-content: center; margin-left: 8px">
|
||||||
<div class="color-title">{{ t('chart.textColor') }}</div>
|
<div class="color-title">{{ t('chart.textColor') }}</div>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
is-custom
|
is-custom
|
||||||
size="large"
|
:trigger-width="60"
|
||||||
v-model="item.color"
|
v-model="item.color"
|
||||||
show-alpha
|
show-alpha
|
||||||
class="color-picker-style"
|
class="color-picker-style"
|
||||||
@ -192,14 +192,14 @@ init()
|
|||||||
</div>
|
</div>
|
||||||
<div style="display: flex; align-items: center; justify-content: center; margin-left: 8px">
|
<div style="display: flex; align-items: center; justify-content: center; margin-left: 8px">
|
||||||
<el-button
|
<el-button
|
||||||
class="circle-button circle-buttons"
|
class="circle-button"
|
||||||
type="text"
|
type="text"
|
||||||
circle
|
circle
|
||||||
style="float: right"
|
style="float: right"
|
||||||
@click="removeThreshold(index)"
|
@click="removeThreshold(index)"
|
||||||
>
|
>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<Icon name="icon_delete-trash_outlined" class=""
|
<Icon name="icon_delete-trash_outlined"
|
||||||
><icon_deleteTrash_outlined class="svg-icon"
|
><icon_deleteTrash_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,6 +9,7 @@ import YAxisSelector from '@/views/chart/components/editor/editor-style/componen
|
|||||||
import DualYAxisSelector from '@/views/chart/components/editor/editor-style/components/DualYAxisSelector.vue'
|
import DualYAxisSelector from '@/views/chart/components/editor/editor-style/components/DualYAxisSelector.vue'
|
||||||
import TitleSelector from '@/views/chart/components/editor/editor-style/components/TitleSelector.vue'
|
import TitleSelector from '@/views/chart/components/editor/editor-style/components/TitleSelector.vue'
|
||||||
import LegendSelector from '@/views/chart/components/editor/editor-style/components/LegendSelector.vue'
|
import LegendSelector from '@/views/chart/components/editor/editor-style/components/LegendSelector.vue'
|
||||||
|
import SummarySelector from '@/views/chart/components/editor/editor-style/components/SummarySelector.vue'
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import CollapseSwitchItem from '@/components/collapse-switch-item/src/CollapseSwitchItem.vue'
|
import CollapseSwitchItem from '@/components/collapse-switch-item/src/CollapseSwitchItem.vue'
|
||||||
@ -29,6 +30,10 @@ import FlowMapLineSelector from '@/views/chart/components/editor/editor-style/co
|
|||||||
import FlowMapPointSelector from '@/views/chart/components/editor/editor-style/components/FlowMapPointSelector.vue'
|
import FlowMapPointSelector from '@/views/chart/components/editor/editor-style/components/FlowMapPointSelector.vue'
|
||||||
import CommonBorderSetting from '@/custom-component/common/CommonBorderSetting.vue'
|
import CommonBorderSetting from '@/custom-component/common/CommonBorderSetting.vue'
|
||||||
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
||||||
|
import BulletTargetSelector from '@/views/chart/components/editor/editor-style/components/bullet/BulletTargetSelector.vue'
|
||||||
|
import BulletMeasureSelector from '@/views/chart/components/editor/editor-style/components/bullet/BulletMeasureSelector.vue'
|
||||||
|
import BulletRangeSelector from '@/views/chart/components/editor/editor-style/components/bullet/BulletRangeSelector.vue'
|
||||||
|
|
||||||
const snapshotStore = snapshotStoreWithOut()
|
const snapshotStore = snapshotStoreWithOut()
|
||||||
|
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
@ -196,7 +201,7 @@ const onBackgroundChange = (val, prop) => {
|
|||||||
state.initReady && emit('onBackgroundChange', val, prop)
|
state.initReady && emit('onBackgroundChange', val, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onActiveChange = val => {
|
const onActiveChange = () => {
|
||||||
snapshotStore.recordSnapshotCache('onActiveChange')
|
snapshotStore.recordSnapshotCache('onActiveChange')
|
||||||
state.initReady &&
|
state.initReady &&
|
||||||
emit('onStyleAttrChange', {
|
emit('onStyleAttrChange', {
|
||||||
@ -288,6 +293,40 @@ watch(
|
|||||||
@onMiscChange="onMiscChange"
|
@onMiscChange="onMiscChange"
|
||||||
/>
|
/>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
|
<div v-if="showProperties('bullet-graph-selector')">
|
||||||
|
<el-collapse-item :effect="themes" name="bullet" :title="t('chart.progress_target')">
|
||||||
|
<bullet-target-selector
|
||||||
|
:themes="themes"
|
||||||
|
:chart="chart"
|
||||||
|
:selector-type="'target'"
|
||||||
|
@onBasicStyleChange="onBasicStyleChange"
|
||||||
|
@onMiscChange="onMiscChange"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item :effect="themes" name="measure" :title="t('chart.progress_current')">
|
||||||
|
<bullet-measure-selector
|
||||||
|
:themes="themes"
|
||||||
|
:chart="chart"
|
||||||
|
:selector-type="'measure'"
|
||||||
|
@onBasicStyleChange="onBasicStyleChange"
|
||||||
|
@onMiscChange="onMiscChange"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
style="margin-bottom: 0 !important"
|
||||||
|
:effect="themes"
|
||||||
|
name="range"
|
||||||
|
:title="t('chart.range_bg')"
|
||||||
|
>
|
||||||
|
<bullet-range-selector
|
||||||
|
:themes="themes"
|
||||||
|
:chart="chart"
|
||||||
|
:selector-type="'range'"
|
||||||
|
@onBasicStyleChange="onBasicStyleChange"
|
||||||
|
@onMiscChange="onMiscChange"
|
||||||
|
/>
|
||||||
|
</el-collapse-item>
|
||||||
|
</div>
|
||||||
<collapse-switch-item
|
<collapse-switch-item
|
||||||
:themes="themes"
|
:themes="themes"
|
||||||
v-model="chart.customStyle.text.show"
|
v-model="chart.customStyle.text.show"
|
||||||
@ -450,12 +489,8 @@ watch(
|
|||||||
@onLabelChange="onLabelChange"
|
@onLabelChange="onLabelChange"
|
||||||
/>
|
/>
|
||||||
</collapse-switch-item>
|
</collapse-switch-item>
|
||||||
<!-- tooltip 为鼠标悬停 移动端table看不到效果 不再单独配置 -->
|
|
||||||
<collapse-switch-item
|
<collapse-switch-item
|
||||||
v-if="
|
v-if="showProperties('tooltip-selector')"
|
||||||
showProperties('tooltip-selector') &&
|
|
||||||
(!mobileInPc || (mobileInPc && chart.type.indexOf('table') === -1))
|
|
||||||
"
|
|
||||||
v-model="chart.customAttr.tooltip.show"
|
v-model="chart.customAttr.tooltip.show"
|
||||||
:themes="themes"
|
:themes="themes"
|
||||||
:change-model="chart.customAttr.tooltip"
|
:change-model="chart.customAttr.tooltip"
|
||||||
@ -616,6 +651,23 @@ watch(
|
|||||||
@onChangeYAxisExtForm="onChangeYAxisExtForm"
|
@onChangeYAxisExtForm="onChangeYAxisExtForm"
|
||||||
/>
|
/>
|
||||||
</collapse-switch-item>
|
</collapse-switch-item>
|
||||||
|
|
||||||
|
<collapse-switch-item
|
||||||
|
:themes="themes"
|
||||||
|
v-if="showProperties('summary-selector')"
|
||||||
|
v-model="chart.customAttr.basicStyle.showSummary"
|
||||||
|
:change-model="chart.customAttr.basicStyle"
|
||||||
|
@modelChange="val => onBasicStyleChange({ data: val }, 'showSummary')"
|
||||||
|
:title="t('chart.table_summary')"
|
||||||
|
name="summary"
|
||||||
|
>
|
||||||
|
<summary-selector
|
||||||
|
:property-inner="propertyInnerAll['summary-selector']"
|
||||||
|
:themes="themes"
|
||||||
|
:chart="chart"
|
||||||
|
@onBasicStyleChange="onBasicStyleChange"
|
||||||
|
/>
|
||||||
|
</collapse-switch-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
@ -671,6 +723,6 @@ span {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ed-collapse-item__content) {
|
:deep(.ed-collapse-item__content) {
|
||||||
padding: 16px 8px 0 8px !important;
|
padding: 16px 8px 8px 8px !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -62,7 +62,7 @@ const state = reactive({
|
|||||||
quotaData: []
|
quotaData: []
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = withDefaults(
|
withDefaults(
|
||||||
defineProps<{
|
defineProps<{
|
||||||
themes?: EditorTheme
|
themes?: EditorTheme
|
||||||
}>(),
|
}>(),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { ElMessage } from 'element-plus-secondary'
|
import { ElMessage, ElMessageBox } from 'element-plus-secondary'
|
||||||
import icon_bold_outlined from '@/assets/svg/icon_bold_outlined.svg'
|
import icon_bold_outlined from '@/assets/svg/icon_bold_outlined.svg'
|
||||||
import { uploadFileResult } from '@/api/staticResource'
|
import { uploadFileResult } from '@/api/staticResource'
|
||||||
import icon_italic_outlined from '@/assets/svg/icon_italic_outlined.svg'
|
import icon_italic_outlined from '@/assets/svg/icon_italic_outlined.svg'
|
||||||
@ -15,6 +15,7 @@ import { useEmitt } from '@/hooks/web/useEmitt'
|
|||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import BackgroundOverallCommon from '@/components/visualization/component-background/BackgroundOverallCommon.vue'
|
import BackgroundOverallCommon from '@/components/visualization/component-background/BackgroundOverallCommon.vue'
|
||||||
|
import { isDashboard, isMainCanvas } from '@/utils/canvasUtils'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const styleActiveNames = ref(['basicStyle'])
|
const styleActiveNames = ref(['basicStyle'])
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
@ -40,7 +41,7 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
const { chart, commonBackgroundPop, element } = toRefs(props)
|
const { chart, commonBackgroundPop, element } = toRefs(props)
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const fontSizeList = []
|
const fontSizeList = []
|
||||||
@ -117,6 +118,47 @@ const currentSearch = ref({
|
|||||||
queryConditionWidth: 227
|
queryConditionWidth: 227
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const onFreezeChange = () => {
|
||||||
|
if (element.value.freeze) {
|
||||||
|
let historyFreezeCount = 0
|
||||||
|
dvMainStore.componentData.forEach(item => {
|
||||||
|
if (item.innerType === 'VQuery' && item.id !== element.value.id && item.freeze) {
|
||||||
|
historyFreezeCount++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (historyFreezeCount) {
|
||||||
|
ElMessageBox.confirm(t('visualization.filter_freeze_tips'), {
|
||||||
|
confirmButtonType: 'primary',
|
||||||
|
type: 'warning',
|
||||||
|
confirmButtonText: t('common.sure'),
|
||||||
|
cancelButtonText: t('common.cancel'),
|
||||||
|
autofocus: false,
|
||||||
|
showClose: false
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
dvMainStore.componentData.forEach(item => {
|
||||||
|
if (item.innerType === 'VQuery' && item.id !== element.value.id && item.freeze) {
|
||||||
|
item.freeze = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
snapshotStore.recordSnapshotCache('onFreezeChange')
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
element.value.freeze = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
dvMainStore.componentData.forEach(item => {
|
||||||
|
if (item.innerType === 'VQuery' && item.id !== element.value.id && item.freeze) {
|
||||||
|
item.freeze = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
snapshotStore.recordSnapshotCache('onFreezeChange')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snapshotStore.recordSnapshotCache('onFreezeChange')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleCurrentPlaceholder = val => {
|
const handleCurrentPlaceholder = val => {
|
||||||
const obj = props.element.propValue.find(ele => {
|
const obj = props.element.propValue.find(ele => {
|
||||||
return ele.id === val
|
return ele.id === val
|
||||||
@ -158,7 +200,7 @@ onMounted(() => {
|
|||||||
const reUpload = e => {
|
const reUpload = e => {
|
||||||
const file = e.target.files[0]
|
const file = e.target.files[0]
|
||||||
if (file.size > 15000000) {
|
if (file.size > 15000000) {
|
||||||
ElMessage.success('图片大小不符合')
|
ElMessage.success('图片大小不能超过15M')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
uploadFileResult(file, fileUrl => {
|
uploadFileResult(file, fileUrl => {
|
||||||
@ -194,6 +236,12 @@ const checkItalic = type => {
|
|||||||
chart.value.customStyle.component[type] = chart.value.customStyle.component[type] ? '' : 'italic'
|
chart.value.customStyle.component[type] = chart.value.customStyle.component[type] ? '' : 'italic'
|
||||||
}
|
}
|
||||||
const initParams = () => {
|
const initParams = () => {
|
||||||
|
if (!chart.value.customStyle.component.hasOwnProperty('queryConditionHeight')) {
|
||||||
|
chart.value.customStyle.component = {
|
||||||
|
...chart.value.customStyle.component,
|
||||||
|
queryConditionHeight: 32
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!chart.value.customStyle.component.hasOwnProperty('labelShow')) {
|
if (!chart.value.customStyle.component.hasOwnProperty('labelShow')) {
|
||||||
chart.value.customStyle.component = {
|
chart.value.customStyle.component = {
|
||||||
...chart.value.customStyle.component,
|
...chart.value.customStyle.component,
|
||||||
@ -251,7 +299,7 @@ const onTitleChange = () => {
|
|||||||
<el-row class="de-collapse-style">
|
<el-row class="de-collapse-style">
|
||||||
<el-collapse v-model="styleActiveNames" class="style-collapse">
|
<el-collapse v-model="styleActiveNames" class="style-collapse">
|
||||||
<el-collapse-item :effect="themes" name="basicStyle" :title="t('chart.basic_style')">
|
<el-collapse-item :effect="themes" name="basicStyle" :title="t('chart.basic_style')">
|
||||||
<el-form @keydown.stop.prevent.enter label-position="top">
|
<el-form size="small" @keydown.stop.prevent.enter label-position="top">
|
||||||
<el-form-item class="form-item margin-bottom-8" :class="'form-item-' + themes">
|
<el-form-item class="form-item margin-bottom-8" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -289,6 +337,26 @@ const onTitleChange = () => {
|
|||||||
:predefine="COLOR_PANEL"
|
:predefine="COLOR_PANEL"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="!mobileInPc && isDashboard() && isMainCanvas(element.canvasId)"
|
||||||
|
class="form-item margin-bottom-8"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
:label="t('visualization.query_position')"
|
||||||
|
>
|
||||||
|
<el-radio-group
|
||||||
|
v-model="element.freeze"
|
||||||
|
:effect="themes"
|
||||||
|
size="small"
|
||||||
|
@change="onFreezeChange"
|
||||||
|
>
|
||||||
|
<el-radio :effect="themes" style="min-width: 80px" :label="true">{{
|
||||||
|
t('visualization.to_top')
|
||||||
|
}}</el-radio>
|
||||||
|
<el-radio :effect="themes" style="min-width: 80px" :label="false">{{
|
||||||
|
t('visualization.default')
|
||||||
|
}}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
<background-overall-common
|
<background-overall-common
|
||||||
:common-background-pop="commonBackgroundPop"
|
:common-background-pop="commonBackgroundPop"
|
||||||
:themes="themes"
|
:themes="themes"
|
||||||
@ -298,7 +366,12 @@ const onTitleChange = () => {
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item :effect="themes" name="addition" :title="t('v_query.query_condition')">
|
<el-collapse-item :effect="themes" name="addition" :title="t('v_query.query_condition')">
|
||||||
<el-form @keydown.stop.prevent.enter label-position="top" style="padding-bottom: 8px">
|
<el-form
|
||||||
|
size="small"
|
||||||
|
@keydown.stop.prevent.enter
|
||||||
|
label-position="top"
|
||||||
|
style="padding-bottom: 8px"
|
||||||
|
>
|
||||||
<el-row :gutter="8">
|
<el-row :gutter="8">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
@ -346,6 +419,19 @@ const onTitleChange = () => {
|
|||||||
controls-position="right"
|
controls-position="right"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:effect="themes"
|
||||||
|
class="form-item"
|
||||||
|
:label="t('visualization.query_condition_height')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
v-model="chart.customStyle.component.queryConditionHeight"
|
||||||
|
:min="32"
|
||||||
|
:effect="themes"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item class="form-item margin-bottom-8" :class="'form-item-' + themes">
|
<el-form-item class="form-item margin-bottom-8" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -366,6 +452,7 @@ const onTitleChange = () => {
|
|||||||
<el-color-picker
|
<el-color-picker
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
:trigger-width="56"
|
:trigger-width="56"
|
||||||
|
style="max-width: 56px; min-width: 56px"
|
||||||
is-custom
|
is-custom
|
||||||
show-alpha
|
show-alpha
|
||||||
v-model="chart.customStyle.component.text"
|
v-model="chart.customStyle.component.text"
|
||||||
@ -423,6 +510,7 @@ const onTitleChange = () => {
|
|||||||
>
|
>
|
||||||
<el-input-number
|
<el-input-number
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
|
:min="100"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
@change="handleCurrentPlaceholderChange"
|
@change="handleCurrentPlaceholderChange"
|
||||||
:disabled="!chart.customStyle.component.placeholderShow || !currentPlaceholder"
|
:disabled="!chart.customStyle.component.placeholderShow || !currentPlaceholder"
|
||||||
@ -441,6 +529,7 @@ const onTitleChange = () => {
|
|||||||
:class="!chart.customStyle.component.labelShow && 'is-disabled'"
|
:class="!chart.customStyle.component.labelShow && 'is-disabled'"
|
||||||
:disabled="!chart.customStyle.component.labelShow"
|
:disabled="!chart.customStyle.component.labelShow"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
style="padding-bottom: 8px"
|
style="padding-bottom: 8px"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
@ -467,6 +556,7 @@ const onTitleChange = () => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
is-custom
|
is-custom
|
||||||
show-alpha
|
show-alpha
|
||||||
|
style="width: 50px"
|
||||||
v-model="chart.customStyle.component.labelColor"
|
v-model="chart.customStyle.component.labelColor"
|
||||||
:predefine="predefineColors"
|
:predefine="predefineColors"
|
||||||
/><el-tooltip
|
/><el-tooltip
|
||||||
@ -545,7 +635,12 @@ const onTitleChange = () => {
|
|||||||
</el-form>
|
</el-form>
|
||||||
</collapse-switch-item>
|
</collapse-switch-item>
|
||||||
<el-collapse-item :effect="themes" name="button" :title="t('commons.button')">
|
<el-collapse-item :effect="themes" name="button" :title="t('commons.button')">
|
||||||
<el-form @keydown.stop.prevent.enter label-position="top" style="padding-bottom: 8px">
|
<el-form
|
||||||
|
size="small"
|
||||||
|
@keydown.stop.prevent.enter
|
||||||
|
label-position="top"
|
||||||
|
style="padding-bottom: 8px"
|
||||||
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
|
@ -12,11 +12,22 @@ import { cloneDeep, debounce, defaultsDeep } from 'lodash-es'
|
|||||||
import { SERIES_NUMBER_FIELD } from '@antv/s2'
|
import { SERIES_NUMBER_FIELD } from '@antv/s2'
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { isNumber } from 'mathjs'
|
import { isNumber } from 'lodash-es'
|
||||||
import { ElFormItem, ElInputNumber, ElMessage } from 'element-plus-secondary'
|
import { ElFormItem, ElInputNumber, ElMessage } from 'element-plus-secondary'
|
||||||
import { svgStrToUrl } from '../../../js/util'
|
import { svgStrToUrl } from '../../../js/util'
|
||||||
|
import { numberToChineseUnderHundred } from '../../../js/panel/common/common_antv'
|
||||||
|
import { useLocaleStoreWithOut } from '@/store/modules/locale'
|
||||||
|
import { useMapStoreWithOut } from '@/store/modules/map'
|
||||||
|
import { queryMapKeyApi } from '@/api/setting/sysParameter'
|
||||||
|
import {
|
||||||
|
gaodeMapStyleOptions,
|
||||||
|
qqMapStyleOptions,
|
||||||
|
tdtMapStyleOptions
|
||||||
|
} from '@/views/chart/components/js/panel/charts/map/common'
|
||||||
|
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||||
|
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
|
const localeStore = useLocaleStoreWithOut()
|
||||||
const { batchOptStatus, mobileInPc } = storeToRefs(dvMainStore)
|
const { batchOptStatus, mobileInPc } = storeToRefs(dvMainStore)
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -32,7 +43,17 @@ const props = defineProps({
|
|||||||
type: Array<string>
|
type: Array<string>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
const showProperty = prop => {
|
||||||
|
const has = props.propertyInner?.includes(prop)
|
||||||
|
if (!has) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (props.chart.type.includes('map') && mapType.value === 'tianditu' && prop === 'showLabel') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return has
|
||||||
|
}
|
||||||
|
const tableExpandLevelOptions = reactive([{ name: t('chart.expand_all'), value: 'all' }])
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
basicStyleForm: JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE)) as ChartBasicStyle,
|
basicStyleForm: JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE)) as ChartBasicStyle,
|
||||||
@ -46,8 +67,8 @@ const state = reactive({
|
|||||||
fileList: []
|
fileList: []
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
||||||
const changeBasicStyle = (prop?: string, requestData = false) => {
|
const changeBasicStyle = (prop?: string, requestData = false, render = true) => {
|
||||||
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData }, prop)
|
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData, render }, prop)
|
||||||
}
|
}
|
||||||
const onAlphaChange = v => {
|
const onAlphaChange = v => {
|
||||||
const _v = parseInt(v)
|
const _v = parseInt(v)
|
||||||
@ -106,6 +127,28 @@ const init = () => {
|
|||||||
state.customColor = state.basicStyleForm.colors[0]
|
state.customColor = state.basicStyleForm.colors[0]
|
||||||
state.colorIndex = 0
|
state.colorIndex = 0
|
||||||
}
|
}
|
||||||
|
if (basicStyle.tableLayoutMode === 'tree') {
|
||||||
|
tableExpandLevelOptions.splice(1)
|
||||||
|
let maxLevel = props.chart.xAxis?.length
|
||||||
|
if (isNumber(basicStyle.defaultExpandLevel)) {
|
||||||
|
maxLevel = Math.max(maxLevel, basicStyle.defaultExpandLevel)
|
||||||
|
}
|
||||||
|
for (let i = 1; i <= maxLevel; i++) {
|
||||||
|
let name = t('chart.level_label', { num: i })
|
||||||
|
if (localeStore.getCurrentLocale.lang !== 'en') {
|
||||||
|
name = t('chart.level_label', { num: numberToChineseUnderHundred(i) })
|
||||||
|
}
|
||||||
|
tableExpandLevelOptions.push({ name, value: i })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const lastPageInfo = dvMainStore.getViewPageInfo(props.chart.id)
|
||||||
|
if (lastPageInfo) {
|
||||||
|
if (lastPageInfo.pageSize && lastPageInfo.pageSize !== state.basicStyleForm.tablePageSize) {
|
||||||
|
state.basicStyleForm.tablePageSize = lastPageInfo.pageSize
|
||||||
|
changeBasicStyle('tablePageSize', false, false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
initTableColumnWidth()
|
initTableColumnWidth()
|
||||||
}
|
}
|
||||||
const debouncedInit = debounce(init, 500)
|
const debouncedInit = debounce(init, 500)
|
||||||
@ -226,6 +269,8 @@ const changeFieldColumnWidth = () => {
|
|||||||
const pageSizeOptions = [
|
const pageSizeOptions = [
|
||||||
{ name: '10' + t('chart.table_page_size_unit'), value: 10 },
|
{ name: '10' + t('chart.table_page_size_unit'), value: 10 },
|
||||||
{ name: '20' + t('chart.table_page_size_unit'), value: 20 },
|
{ name: '20' + t('chart.table_page_size_unit'), value: 20 },
|
||||||
|
{ name: '30' + t('chart.table_page_size_unit'), value: 30 },
|
||||||
|
{ name: '40' + t('chart.table_page_size_unit'), value: 40 },
|
||||||
{ name: '50' + t('chart.table_page_size_unit'), value: 50 },
|
{ name: '50' + t('chart.table_page_size_unit'), value: 50 },
|
||||||
{ name: '100' + t('chart.table_page_size_unit'), value: 100 }
|
{ name: '100' + t('chart.table_page_size_unit'), value: 100 }
|
||||||
]
|
]
|
||||||
@ -238,17 +283,34 @@ const symbolOptions = [
|
|||||||
{ name: t('chart.line_symbol_triangle'), value: 'triangle' },
|
{ name: t('chart.line_symbol_triangle'), value: 'triangle' },
|
||||||
{ name: t('chart.line_symbol_diamond'), value: 'diamond' }
|
{ name: t('chart.line_symbol_diamond'), value: 'diamond' }
|
||||||
]
|
]
|
||||||
const mapStyleOptions = [
|
|
||||||
{ name: t('chart.map_style_normal'), value: 'normal' },
|
const mapStore = useMapStoreWithOut()
|
||||||
{ name: t('chart.map_style_darkblue'), value: 'darkblue' },
|
|
||||||
{ name: t('chart.map_style_light'), value: 'light' },
|
const getMapKey = async () => {
|
||||||
{ name: t('chart.map_style_dark'), value: 'dark' },
|
if (!mapStore.mapKey.key) {
|
||||||
{ name: t('chart.map_style_fresh'), value: 'fresh' },
|
await queryMapKeyApi().then(res => mapStore.setKey(res.data))
|
||||||
{ name: t('chart.map_style_grey'), value: 'grey' },
|
}
|
||||||
{ name: t('chart.map_style_blue'), value: 'blue' },
|
if (mapStore.mapKey.securityCode) {
|
||||||
{ name: '卫星地图', value: 'Satellite' },
|
window._AMapSecurityConfig = {
|
||||||
{ name: t('commons.custom'), value: 'custom' }
|
securityJsCode: mapStore.mapKey.securityCode
|
||||||
]
|
}
|
||||||
|
}
|
||||||
|
return mapStore.mapKey
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapType = ref<string>(undefined)
|
||||||
|
|
||||||
|
const mapStyleOptions = computed(() => {
|
||||||
|
switch (mapType.value) {
|
||||||
|
case 'tianditu':
|
||||||
|
return tdtMapStyleOptions
|
||||||
|
case 'qq':
|
||||||
|
return qqMapStyleOptions
|
||||||
|
default:
|
||||||
|
return gaodeMapStyleOptions
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const heatMapTypeOptions = [
|
const heatMapTypeOptions = [
|
||||||
{ name: t('chart.heatmap_classics'), value: 'heatmap' },
|
{ name: t('chart.heatmap_classics'), value: 'heatmap' },
|
||||||
{ name: t('chart.heatmap3D'), value: 'heatmap3D' }
|
{ name: t('chart.heatmap3D'), value: 'heatmap3D' }
|
||||||
@ -265,12 +327,51 @@ const mergeCell = computed(() => {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const preventInvalidKeydown = event => {
|
||||||
|
const invalidKeys = ['e', 'E', '+', '-', '.']
|
||||||
|
if (invalidKeys.includes(event.key)) {
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 验证输入值
|
||||||
|
const validateInput = (value, field) => {
|
||||||
|
if (value === '') {
|
||||||
|
state.basicStyleForm[field] = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let num = parseInt(value, 10)
|
||||||
|
|
||||||
|
if (isNaN(num)) {
|
||||||
|
num = 1
|
||||||
|
} else if (num < 1) {
|
||||||
|
num = 1
|
||||||
|
} else if (num > 100) {
|
||||||
|
num = 100
|
||||||
|
}
|
||||||
|
state.basicStyleForm[field] = num
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init()
|
init()
|
||||||
|
getMapKey().then(res => {
|
||||||
|
if (res) {
|
||||||
|
mapType.value = res.mapType
|
||||||
|
}
|
||||||
|
})
|
||||||
|
useEmitt({
|
||||||
|
name: 'chart-type-change',
|
||||||
|
callback: () => {
|
||||||
|
if (['topRoundAngle', 'roundAngle'].includes(state.basicStyleForm.radiusColumnBar)) {
|
||||||
|
state.basicStyleForm.radiusColumnBar = 'roundAngle'
|
||||||
|
changeBasicStyle('radiusColumnBar')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div style="width: 100%">
|
<el-form size="small" style="width: 100%">
|
||||||
<template v-if="showProperty('colors')">
|
<template v-if="showProperty('colors')">
|
||||||
<custom-color-style-select
|
<custom-color-style-select
|
||||||
v-model="state"
|
v-model="state"
|
||||||
@ -308,7 +409,53 @@ onMounted(() => {
|
|||||||
<el-radio label="tree" :effect="themes">{{ t('chart.table_layout_tree') }}</el-radio>
|
<el-radio label="tree" :effect="themes">{{ t('chart.table_layout_tree') }}</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="form-item"
|
||||||
|
v-if="showProperty('tableLayoutMode') && state.basicStyleForm.tableLayoutMode === 'tree'"
|
||||||
|
:label="t('chart.default_expand_level')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.basicStyleForm.defaultExpandLevel"
|
||||||
|
@change="changeBasicStyle('defaultExpandLevel')"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in tableExpandLevelOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="form-item"
|
||||||
|
v-if="showProperty('quotaPosition')"
|
||||||
|
:label="t('chart.quota_position')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-radio-group
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.basicStyleForm.quotaPosition"
|
||||||
|
@change="changeBasicStyle('quotaPosition')"
|
||||||
|
>
|
||||||
|
<el-radio label="col" :effect="themes">{{ t('chart.quota_position_col') }}</el-radio>
|
||||||
|
<el-radio label="row" :effect="themes">{{ t('chart.quota_position_row') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="showProperty('quotaColLabel') && state.basicStyleForm.quotaPosition === 'row'"
|
||||||
|
class="form-item"
|
||||||
|
:label="t('chart.quota_col_label')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.basicStyleForm.quotaColLabel"
|
||||||
|
@change="changeBasicStyle('quotaColLabel')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<div class="alpha-setting" v-if="showProperty('alpha')">
|
<div class="alpha-setting" v-if="showProperty('alpha')">
|
||||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||||
{{ t('chart.not_alpha') }}
|
{{ t('chart.not_alpha') }}
|
||||||
@ -353,9 +500,16 @@ onMounted(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.basicStyleForm.radiusColumnBar"
|
v-model="state.basicStyleForm.radiusColumnBar"
|
||||||
@change="changeBasicStyle('radiusColumnBar')"
|
@change="changeBasicStyle('radiusColumnBar')"
|
||||||
|
class="radius-class"
|
||||||
>
|
>
|
||||||
<el-radio label="rightAngle" :effect="themes">{{ t('chart.rightAngle') }}</el-radio>
|
<el-radio label="rightAngle" :effect="themes">{{ t('chart.rightAngle') }}</el-radio>
|
||||||
<el-radio label="roundAngle" :effect="themes">{{ t('chart.roundAngle') }}</el-radio>
|
<el-radio label="roundAngle" :effect="themes">{{ t('chart.roundAngle') }}</el-radio>
|
||||||
|
<el-radio
|
||||||
|
v-if="!props.chart.type.includes('-stack')"
|
||||||
|
label="topRoundAngle"
|
||||||
|
:effect="themes"
|
||||||
|
>{{ t('chart.topRoundAngle') }}</el-radio
|
||||||
|
>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -434,7 +588,7 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div class="alpha-setting">
|
<div class="alpha-setting" v-if="mapType !== 'tianditu'">
|
||||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||||
{{ t('chart.chart_map') + ' ' + t('chart.map_pitch') }}
|
{{ t('chart.chart_map') + ' ' + t('chart.map_pitch') }}
|
||||||
</label>
|
</label>
|
||||||
@ -726,7 +880,7 @@ onMounted(() => {
|
|||||||
<el-radio-group
|
<el-radio-group
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.basicStyleForm.tablePageStyle"
|
v-model="state.basicStyleForm.tablePageStyle"
|
||||||
@change="changeBasicStyle('tablePageStyle', true)"
|
@change="changeBasicStyle('tablePageStyle', false)"
|
||||||
>
|
>
|
||||||
<el-radio :effect="themes" label="simple">{{ t('chart.page_pager_simple') }}</el-radio>
|
<el-radio :effect="themes" label="simple">{{ t('chart.page_pager_simple') }}</el-radio>
|
||||||
<el-radio :effect="themes" label="general">{{ t('chart.page_pager_general') }}</el-radio>
|
<el-radio :effect="themes" label="general">{{ t('chart.page_pager_general') }}</el-radio>
|
||||||
@ -824,34 +978,6 @@ onMounted(() => {
|
|||||||
<template #append>%</template>
|
<template #append>%</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
|
||||||
v-if="showProperty('showSummary')"
|
|
||||||
class="form-item"
|
|
||||||
:class="'form-item-' + themes"
|
|
||||||
>
|
|
||||||
<el-checkbox
|
|
||||||
size="small"
|
|
||||||
:effect="themes"
|
|
||||||
v-model="state.basicStyleForm.showSummary"
|
|
||||||
@change="changeBasicStyle('showSummary')"
|
|
||||||
>
|
|
||||||
{{ t('chart.table_show_summary') }}
|
|
||||||
</el-checkbox>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item
|
|
||||||
v-if="showProperty('summaryLabel') && state.basicStyleForm.showSummary"
|
|
||||||
:label="t('chart.table_summary_label')"
|
|
||||||
:class="'form-item-' + themes"
|
|
||||||
class="form-item"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="state.basicStyleForm.summaryLabel"
|
|
||||||
type="text"
|
|
||||||
:effect="themes"
|
|
||||||
:max-length="10"
|
|
||||||
@blur="changeBasicStyle('summaryLabel')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item v-if="showProperty('autoWrap')" class="form-item" :class="'form-item-' + themes">
|
<el-form-item v-if="showProperty('autoWrap')" class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
size="small"
|
size="small"
|
||||||
@ -1347,7 +1473,9 @@ onMounted(() => {
|
|||||||
:max="100"
|
:max="100"
|
||||||
class="basic-input-number"
|
class="basic-input-number"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
|
@input="validateInput($event, 'innerRadius')"
|
||||||
@change="changeBasicStyle('innerRadius')"
|
@change="changeBasicStyle('innerRadius')"
|
||||||
|
@keydown="preventInvalidKeydown"
|
||||||
>
|
>
|
||||||
<template #suffix> % </template>
|
<template #suffix> % </template>
|
||||||
</el-input>
|
</el-input>
|
||||||
@ -1382,7 +1510,9 @@ onMounted(() => {
|
|||||||
:max="100"
|
:max="100"
|
||||||
class="basic-input-number"
|
class="basic-input-number"
|
||||||
:controls="false"
|
:controls="false"
|
||||||
|
@input="validateInput($event, 'radius')"
|
||||||
@change="changeBasicStyle('radius')"
|
@change="changeBasicStyle('radius')"
|
||||||
|
@keydown="preventInvalidKeydown"
|
||||||
>
|
>
|
||||||
<template #suffix> % </template>
|
<template #suffix> % </template>
|
||||||
</el-input>
|
</el-input>
|
||||||
@ -1454,7 +1584,7 @@ onMounted(() => {
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<!-- circle-packing end -->
|
<!-- circle-packing end -->
|
||||||
</div>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.color-picker-style {
|
.color-picker-style {
|
||||||
@ -1628,4 +1758,12 @@ onMounted(() => {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
.radius-class {
|
||||||
|
:deep(.ed-radio) {
|
||||||
|
margin-right: 30px !important;
|
||||||
|
}
|
||||||
|
.ed-radio:last-child {
|
||||||
|
margin-right: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -234,11 +234,18 @@ const changeColorOption = (option?) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const resetCustomColor = () => {
|
const resetCustomColor = () => {
|
||||||
if (props.chart.type.includes('map')) {
|
const { type } = props.chart
|
||||||
|
const { basicStyleForm } = state.value
|
||||||
|
|
||||||
|
if (type.includes('map')) {
|
||||||
changeColorOption()
|
changeColorOption()
|
||||||
} else {
|
} else {
|
||||||
state.value.basicStyleForm[seriesColorName.value] = []
|
basicStyleForm[seriesColorName.value] = []
|
||||||
changeBasicStyle(seriesColorName.value)
|
changeBasicStyle(seriesColorName.value)
|
||||||
|
const colorScheme = basicStyleForm[colorSchemeName.value]
|
||||||
|
basicStyleForm[colorsName.value] =
|
||||||
|
colorCases.find(ele => ele.value === colorScheme)?.colors ?? colorCases[0].colors
|
||||||
|
changeBasicStyle(colorsName.value)
|
||||||
setupSeriesColor()
|
setupSeriesColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,7 +307,8 @@ const colorItemBorderColor = (index, state) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<el-form
|
||||||
|
size="small"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
:style="{ 'margin-bottom': customColorExtendSettingOpened ? '16px' : 0 }"
|
:style="{ 'margin-bottom': customColorExtendSettingOpened ? '16px' : 0 }"
|
||||||
>
|
>
|
||||||
@ -510,7 +518,7 @@ const colorItemBorderColor = (index, state) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</teleport>
|
</teleport>
|
||||||
</div>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@ -523,6 +531,7 @@ const colorItemBorderColor = (index, state) => {
|
|||||||
.custom-color-selector {
|
.custom-color-selector {
|
||||||
:deep(.ed-input__prefix) {
|
:deep(.ed-input__prefix) {
|
||||||
width: calc(100% - 22px);
|
width: calc(100% - 22px);
|
||||||
|
.ed-input__prefix,
|
||||||
.ed-input__prefix-inner {
|
.ed-input__prefix-inner {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, PropType, reactive, watch, ref } from 'vue'
|
import { onMounted, PropType, reactive, watch, ref } from 'vue'
|
||||||
import {
|
import { DEFAULT_BASIC_STYLE, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
||||||
COLOR_PANEL,
|
|
||||||
DEFAULT_BASIC_STYLE,
|
|
||||||
DEFAULT_MISC
|
|
||||||
} from '@/views/chart/components/editor/util/chart'
|
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import CustomColorStyleSelect from '@/views/chart/components/editor/editor-style/components/CustomColorStyleSelect.vue'
|
import CustomColorStyleSelect from '@/views/chart/components/editor/editor-style/components/CustomColorStyleSelect.vue'
|
||||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import {
|
import {
|
||||||
CHART_MIX_DEFAULT_BASIC_STYLE,
|
CHART_MIX_DEFAULT_BASIC_STYLE,
|
||||||
MixChartBasicStyle
|
MixChartBasicStyle
|
||||||
} from '@/views/chart/components/js/panel/charts/others/chart-mix-common'
|
} from '@/views/chart/components/js/panel/charts/others/chart-mix-common'
|
||||||
|
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
|
||||||
const { batchOptStatus } = storeToRefs(dvMainStore)
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
chart: {
|
chart: {
|
||||||
@ -33,7 +25,6 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
const showProperty = prop => props.propertyInner?.includes(prop)
|
||||||
const predefineColors = COLOR_PANEL
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
basicStyleForm: JSON.parse(JSON.stringify(CHART_MIX_DEFAULT_BASIC_STYLE)) as MixChartBasicStyle,
|
basicStyleForm: JSON.parse(JSON.stringify(CHART_MIX_DEFAULT_BASIC_STYLE)) as MixChartBasicStyle,
|
||||||
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr,
|
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr,
|
||||||
@ -128,6 +119,12 @@ const init = () => {
|
|||||||
state.customColor = state.basicStyleForm.colors[0]
|
state.customColor = state.basicStyleForm.colors[0]
|
||||||
state.colorIndex = 0
|
state.colorIndex = 0
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
props.chart.type.includes('-stack') &&
|
||||||
|
state.basicStyleForm.radiusColumnBar === 'topRoundAngle'
|
||||||
|
) {
|
||||||
|
state.basicStyleForm.radiusColumnBar = 'roundAngle'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const configCompat = (basicStyle: ChartBasicStyle) => {
|
const configCompat = (basicStyle: ChartBasicStyle) => {
|
||||||
// 悬浮改为图例和缩放按钮
|
// 悬浮改为图例和缩放按钮
|
||||||
@ -149,7 +146,7 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div style="width: 100%">
|
<el-form size="small" style="width: 100%">
|
||||||
<el-tabs v-model="activeName" id="axis-tabs" stretch>
|
<el-tabs v-model="activeName" id="axis-tabs" stretch>
|
||||||
<el-tab-pane :label="t('chart.yAxisLeft')" name="left">
|
<el-tab-pane :label="t('chart.yAxisLeft')" name="left">
|
||||||
<template v-if="showProperty('colors')">
|
<template v-if="showProperty('colors')">
|
||||||
@ -224,9 +221,17 @@ onMounted(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.basicStyleForm.radiusColumnBar"
|
v-model="state.basicStyleForm.radiusColumnBar"
|
||||||
@change="changeBasicStyle('radiusColumnBar')"
|
@change="changeBasicStyle('radiusColumnBar')"
|
||||||
|
class="radius-class"
|
||||||
>
|
>
|
||||||
<el-radio label="rightAngle" :effect="themes">{{ t('chart.rightAngle') }}</el-radio>
|
<el-radio label="rightAngle" :effect="themes">{{ t('chart.rightAngle') }}</el-radio>
|
||||||
<el-radio label="roundAngle" :effect="themes">{{ t('chart.roundAngle') }}</el-radio>
|
<el-radio label="roundAngle" :effect="themes">{{ t('chart.roundAngle') }}</el-radio>
|
||||||
|
<el-radio
|
||||||
|
v-if="!props.chart.type.includes('-stack')"
|
||||||
|
label="topRoundAngle"
|
||||||
|
:effect="themes"
|
||||||
|
>
|
||||||
|
{{ t('chart.topRoundAngle') }}</el-radio
|
||||||
|
>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="alpha-setting" v-if="showProperty('columnWidthRatio')">
|
<div class="alpha-setting" v-if="showProperty('columnWidthRatio')">
|
||||||
@ -462,7 +467,7 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.form-item {
|
.form-item {
|
||||||
@ -552,4 +557,12 @@ onMounted(() => {
|
|||||||
border-top: none !important;
|
border-top: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.radius-class {
|
||||||
|
:deep(.ed-radio) {
|
||||||
|
margin-right: 30px !important;
|
||||||
|
}
|
||||||
|
.ed-radio:last-child {
|
||||||
|
margin-right: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { computed, onMounted, PropType, reactive, ref, watch } from 'vue'
|
import { onMounted, PropType, reactive, ref, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import {
|
import {
|
||||||
COLOR_PANEL,
|
|
||||||
DEFAULT_YAXIS_EXT_STYLE,
|
DEFAULT_YAXIS_EXT_STYLE,
|
||||||
DEFAULT_YAXIS_STYLE
|
DEFAULT_YAXIS_STYLE
|
||||||
} from '@/views/chart/components/editor/util/chart'
|
} from '@/views/chart/components/editor/util/chart'
|
||||||
import { formatterType, unitType } from '@/views/chart/components/js/formatter'
|
|
||||||
import { ElMessage } from 'element-plus-secondary'
|
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import DualYAxisSelectorInner from './DualYAxisSelectorInner.vue'
|
import DualYAxisSelectorInner from './DualYAxisSelectorInner.vue'
|
||||||
|
|
||||||
|
@ -3,8 +3,14 @@ import icon_info_outlined from '@/assets/svg/icon_info_outlined.svg'
|
|||||||
import { computed, onMounted, reactive, watch } from 'vue'
|
import { computed, onMounted, reactive, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_YAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_PANEL, DEFAULT_YAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
import { formatterType, unitType } from '@/views/chart/components/js/formatter'
|
import {
|
||||||
import { ElMessage } from 'element-plus-secondary'
|
isEnLocal,
|
||||||
|
formatterType,
|
||||||
|
getUnitTypeList,
|
||||||
|
initFormatCfgUnit,
|
||||||
|
onChangeFormatCfgUnitLanguage
|
||||||
|
} from '@/views/chart/components/js/formatter'
|
||||||
|
import { ElFormItem, ElMessage } from 'element-plus-secondary'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -25,9 +31,8 @@ const props = withDefaults(
|
|||||||
|
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const typeList = formatterType
|
const typeList = formatterType
|
||||||
const unitList = unitType
|
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
axisForm: JSON.parse(JSON.stringify(DEFAULT_YAXIS_STYLE))
|
axisForm: JSON.parse(JSON.stringify(DEFAULT_YAXIS_STYLE))
|
||||||
@ -77,8 +82,14 @@ const changeAxisStyle = prop => {
|
|||||||
emit('onChangeYAxisForm', state.axisForm, prop)
|
emit('onChangeYAxisForm', state.axisForm, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeUnitLanguage(cfg: BaseFormatter, lang, prop: string) {
|
||||||
|
onChangeFormatCfgUnitLanguage(cfg, lang)
|
||||||
|
changeAxisStyle(prop)
|
||||||
|
}
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
state.axisForm = JSON.parse(JSON.stringify(props.form))
|
state.axisForm = JSON.parse(JSON.stringify(props.form))
|
||||||
|
initFormatCfgUnit(state.axisForm.axisLabelFormatter)
|
||||||
}
|
}
|
||||||
|
|
||||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
const showProperty = prop => props.propertyInner?.includes(prop)
|
||||||
@ -302,6 +313,49 @@ onMounted(() => {
|
|||||||
{{ t('chart.axis_show') }}
|
{{ t('chart.axis_show') }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<div style="padding-left: 22px" v-if="showProperty('axisLine')">
|
||||||
|
<div style="flex: 1; display: flex">
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-right: 4px">
|
||||||
|
<el-color-picker
|
||||||
|
:disabled="!state.axisForm.axisLine.show"
|
||||||
|
v-model="state.axisForm.axisLine.lineStyle.color"
|
||||||
|
:predefine="predefineColors"
|
||||||
|
:effect="themes"
|
||||||
|
@change="changeAxisStyle('axisLine.lineStyle.color')"
|
||||||
|
is-custom
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding: 0 4px">
|
||||||
|
<el-select
|
||||||
|
:disabled="!state.axisForm.axisLine.show"
|
||||||
|
style="width: 62px"
|
||||||
|
:effect="props.themes"
|
||||||
|
v-model="state.axisForm.axisLine.lineStyle.style"
|
||||||
|
@change="changeAxisStyle('axisLine.lineStyle.style')"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="option in splitLineStyle"
|
||||||
|
:key="option.value"
|
||||||
|
:value="option.value"
|
||||||
|
:label="option.label"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
|
||||||
|
<el-input-number
|
||||||
|
:disabled="!state.axisForm.axisLine.show"
|
||||||
|
style="width: 70px"
|
||||||
|
:effect="props.themes"
|
||||||
|
v-model="state.axisForm.axisLine.lineStyle.width"
|
||||||
|
:min="1"
|
||||||
|
:max="10"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeAxisStyle('axisLine.lineStyle.width')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item form-item-checkbox"
|
class="form-item form-item-checkbox"
|
||||||
:class="{
|
:class="{
|
||||||
@ -473,13 +527,38 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="
|
v-if="
|
||||||
state.axisForm.axisLabel.show && state.axisForm.axisLabelFormatter.type !== 'percent'
|
state.axisForm.axisLabel.show && state.axisForm.axisLabelFormatter.type !== 'percent'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.axisForm.axisLabelFormatter.unitLanguage"
|
||||||
|
:placeholder="t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeUnitLanguage(
|
||||||
|
state.axisForm.axisLabelFormatter,
|
||||||
|
v,
|
||||||
|
'axisLabelFormatter'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
@ -490,18 +569,22 @@ onMounted(() => {
|
|||||||
v-model="state.axisForm.axisLabelFormatter.unit"
|
v-model="state.axisForm.axisLabelFormatter.unit"
|
||||||
:placeholder="t('chart.pls_select_field')"
|
:placeholder="t('chart.pls_select_field')"
|
||||||
size="small"
|
size="small"
|
||||||
@change="changeAxisStyle('axisLabelFormatter.unit')"
|
@change="changeAxisStyle('axisLabelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitList"
|
v-for="item in getUnitTypeList(
|
||||||
|
state.axisForm.axisLabelFormatter.unitLanguage
|
||||||
|
)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
@ -519,6 +602,7 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
import { onMounted, PropType, reactive, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import {
|
import {
|
||||||
COLOR_PANEL,
|
COLOR_PANEL,
|
||||||
DEFAULT_BASIC_STYLE,
|
DEFAULT_BASIC_STYLE,
|
||||||
DEFAULT_MISC
|
DEFAULT_MISC
|
||||||
} from '@/views/chart/components/editor/util/chart'
|
} from '@/views/chart/components/editor/util/chart'
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
|
||||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
chart: {
|
chart: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -34,9 +32,6 @@ const state = reactive({
|
|||||||
lineForm: {} as DeepPartial<ChartMiscAttr['flowMapConfig']['lineConfig']>,
|
lineForm: {} as DeepPartial<ChartMiscAttr['flowMapConfig']['lineConfig']>,
|
||||||
basicStyleForm: {}
|
basicStyleForm: {}
|
||||||
})
|
})
|
||||||
const toolTip = computed(() => {
|
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
|
||||||
})
|
|
||||||
const emit = defineEmits(['onChangeFlowMapLineForm', 'onBasicStyleChange'])
|
const emit = defineEmits(['onChangeFlowMapLineForm', 'onBasicStyleChange'])
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -2,12 +2,10 @@
|
|||||||
import { computed, nextTick, onMounted, PropType, reactive, watch } from 'vue'
|
import { computed, nextTick, onMounted, PropType, reactive, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_PANEL, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
|
||||||
import { ElSpace } from 'element-plus-secondary'
|
import { ElSpace } from 'element-plus-secondary'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
chart: {
|
chart: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -44,7 +42,7 @@ const state = reactive({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['onChangeFlowMapPointForm'])
|
const emit = defineEmits(['onChangeFlowMapPointForm'])
|
||||||
|
|
||||||
@ -85,7 +83,6 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init()
|
init()
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="tsx" setup>
|
<script lang="tsx" setup>
|
||||||
import { computed, nextTick, onMounted, reactive, ref } from 'vue'
|
import { computed, nextTick, onMounted, reactive, ref } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, COLOR_CASES } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_CASES } from '@/views/chart/components/editor/util/chart'
|
||||||
import { ElPopover } from 'element-plus-secondary'
|
import { ElPopover } from 'element-plus-secondary'
|
||||||
import { getMapColorCases } from '@/views/chart/components/js/util'
|
import { getMapColorCases } from '@/views/chart/components/js/util'
|
||||||
|
|
||||||
@ -22,7 +22,6 @@ const props = withDefaults(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
const colorCases = JSON.parse(JSON.stringify(COLOR_CASES))
|
const colorCases = JSON.parse(JSON.stringify(COLOR_CASES))
|
||||||
const predefineColors = JSON.parse(JSON.stringify(COLOR_PANEL))
|
|
||||||
|
|
||||||
const emits = defineEmits(['update:modelValue', 'selectColorCase'])
|
const emits = defineEmits(['update:modelValue', 'selectColorCase'])
|
||||||
const state = computed({
|
const state = computed({
|
||||||
@ -185,6 +184,7 @@ onMounted(() => {
|
|||||||
.custom-color-selector {
|
.custom-color-selector {
|
||||||
:deep(.ed-input__prefix) {
|
:deep(.ed-input__prefix) {
|
||||||
width: calc(100% - 22px);
|
width: calc(100% - 22px);
|
||||||
|
.ed-input__prefix,
|
||||||
.ed-input__prefix-inner {
|
.ed-input__prefix-inner {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import { PropType, computed, onMounted, reactive, watch, nextTick } from 'vue'
|
|||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import {
|
import {
|
||||||
COLOR_PANEL,
|
COLOR_PANEL,
|
||||||
CHART_FONT_FAMILY,
|
|
||||||
CHART_FONT_LETTER_SPACE,
|
CHART_FONT_LETTER_SPACE,
|
||||||
DEFAULT_INDICATOR_NAME_STYLE,
|
DEFAULT_INDICATOR_NAME_STYLE,
|
||||||
DEFAULT_BASIC_STYLE,
|
DEFAULT_BASIC_STYLE,
|
||||||
@ -14,14 +13,9 @@ import {
|
|||||||
} from '@/views/chart/components/editor/util/chart'
|
} from '@/views/chart/components/editor/util/chart'
|
||||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
import Icon from '@/components/icon-custom/src/Icon.vue'
|
import Icon from '@/components/icon-custom/src/Icon.vue'
|
||||||
import { hexColorToRGBA } from '@/views/chart/components/js/util'
|
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
|
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
|
||||||
const { batchOptStatus } = storeToRefs(dvMainStore)
|
|
||||||
const appearanceStore = useAppearanceStoreWithOut()
|
const appearanceStore = useAppearanceStoreWithOut()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -40,7 +34,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['onIndicatorNameChange'])
|
const emit = defineEmits(['onIndicatorNameChange'])
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const fontFamily = CHART_FONT_FAMILY_ORIGIN.concat(
|
const fontFamily = CHART_FONT_FAMILY_ORIGIN.concat(
|
||||||
@ -64,6 +58,12 @@ const fontSizeList = computed(() => {
|
|||||||
value: i
|
value: i
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
for (let i = 70; i <= 210; i += 10) {
|
||||||
|
arr.push({
|
||||||
|
name: i + '',
|
||||||
|
value: i
|
||||||
|
})
|
||||||
|
}
|
||||||
return arr
|
return arr
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -119,6 +119,7 @@ defineExpose({ getFormData })
|
|||||||
:disabled="!state.indicatorNameForm.show"
|
:disabled="!state.indicatorNameForm.show"
|
||||||
:model="state.indicatorNameForm"
|
:model="state.indicatorNameForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
|
@ -20,12 +20,7 @@ import {
|
|||||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
import { ElIcon, ElInput } from 'element-plus-secondary'
|
import { ElIcon, ElInput } from 'element-plus-secondary'
|
||||||
import Icon from '@/components/icon-custom/src/Icon.vue'
|
import Icon from '@/components/icon-custom/src/Icon.vue'
|
||||||
import { hexColorToRGBA } from '@/views/chart/components/js/util'
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
|
||||||
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
|
import { useAppearanceStoreWithOut } from '@/store/modules/appearance'
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
|
||||||
const { batchOptStatus } = storeToRefs(dvMainStore)
|
|
||||||
const appearanceStore = useAppearanceStoreWithOut()
|
const appearanceStore = useAppearanceStoreWithOut()
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@ -46,7 +41,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['onIndicatorChange', 'onBasicStyleChange'])
|
const emit = defineEmits(['onIndicatorChange', 'onBasicStyleChange'])
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const fontFamily = CHART_FONT_FAMILY_ORIGIN.concat(
|
const fontFamily = CHART_FONT_FAMILY_ORIGIN.concat(
|
||||||
@ -61,7 +56,6 @@ const state = reactive({
|
|||||||
indicatorValueForm: JSON.parse(JSON.stringify(DEFAULT_INDICATOR_STYLE)),
|
indicatorValueForm: JSON.parse(JSON.stringify(DEFAULT_INDICATOR_STYLE)),
|
||||||
basicStyleForm: {} as ChartBasicStyle
|
basicStyleForm: {} as ChartBasicStyle
|
||||||
})
|
})
|
||||||
|
|
||||||
const fontSizeList = computed(() => {
|
const fontSizeList = computed(() => {
|
||||||
const arr = []
|
const arr = []
|
||||||
for (let i = 10; i <= 60; i = i + 2) {
|
for (let i = 10; i <= 60; i = i + 2) {
|
||||||
@ -70,6 +64,12 @@ const fontSizeList = computed(() => {
|
|||||||
value: i
|
value: i
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
for (let i = 70; i <= 210; i += 10) {
|
||||||
|
arr.push({
|
||||||
|
name: i + '',
|
||||||
|
value: i
|
||||||
|
})
|
||||||
|
}
|
||||||
return arr
|
return arr
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -126,6 +126,7 @@ defineExpose({ getFormData })
|
|||||||
:disabled="!state.indicatorValueForm.show"
|
:disabled="!state.indicatorValueForm.show"
|
||||||
:model="state.indicatorValueForm"
|
:model="state.indicatorValueForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
|
@ -4,7 +4,13 @@ import { computed, onMounted, PropType, reactive, ref, watch } from 'vue'
|
|||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_PANEL, DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
|
||||||
import { ElFormItem, ElIcon, ElInput, ElSpace } from 'element-plus-secondary'
|
import { ElFormItem, ElIcon, ElInput, ElSpace } from 'element-plus-secondary'
|
||||||
import { formatterType, unitType } from '../../../js/formatter'
|
import {
|
||||||
|
isEnLocal,
|
||||||
|
formatterType,
|
||||||
|
getUnitTypeList,
|
||||||
|
initFormatCfgUnit,
|
||||||
|
onChangeFormatCfgUnitLanguage
|
||||||
|
} from '@/views/chart/components/js/formatter'
|
||||||
import { defaultsDeep, cloneDeep, intersection, union, defaultTo, map, isEmpty } from 'lodash-es'
|
import { defaultsDeep, cloneDeep, intersection, union, defaultTo, map, isEmpty } from 'lodash-es'
|
||||||
import { includesAny } from '../../util/StringUtils'
|
import { includesAny } from '../../util/StringUtils'
|
||||||
import { fieldType } from '@/utils/attr'
|
import { fieldType } from '@/utils/attr'
|
||||||
@ -42,7 +48,7 @@ const props = defineProps({
|
|||||||
})
|
})
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const { batchOptStatus } = storeToRefs(dvMainStore)
|
const { batchOptStatus } = storeToRefs(dvMainStore)
|
||||||
watch(
|
watch(
|
||||||
@ -152,6 +158,7 @@ const initSeriesLabel = () => {
|
|||||||
position: 'top'
|
position: 'top'
|
||||||
} as SeriesFormatter
|
} as SeriesFormatter
|
||||||
if (seriesAxisMap[next[computedIdKey.value]]) {
|
if (seriesAxisMap[next[computedIdKey.value]]) {
|
||||||
|
initFormatCfgUnit(seriesAxisMap[next[computedIdKey.value]].formatterCfg)
|
||||||
tmp = {
|
tmp = {
|
||||||
...tmp,
|
...tmp,
|
||||||
formatterCfg: seriesAxisMap[next[computedIdKey.value]].formatterCfg,
|
formatterCfg: seriesAxisMap[next[computedIdKey.value]].formatterCfg,
|
||||||
@ -253,6 +260,11 @@ const changeLabelAttr = (prop: string, render = true) => {
|
|||||||
emit('onLabelChange', { data: state.labelForm, render }, prop)
|
emit('onLabelChange', { data: state.labelForm, render }, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeLabelUnitLanguage(cfg: BaseFormatter, lang, prop: string, render = true) {
|
||||||
|
onChangeFormatCfgUnitLanguage(cfg, lang)
|
||||||
|
changeLabelAttr(prop, render)
|
||||||
|
}
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
const chart = JSON.parse(JSON.stringify(props.chart))
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
if (chart.customAttr) {
|
if (chart.customAttr) {
|
||||||
@ -260,6 +272,10 @@ const init = () => {
|
|||||||
if (customAttr.label) {
|
if (customAttr.label) {
|
||||||
configCompat(customAttr.label)
|
configCompat(customAttr.label)
|
||||||
state.labelForm = defaultsDeep(customAttr.label, cloneDeep(COMPUTED_DEFAULT_LABEL.value))
|
state.labelForm = defaultsDeep(customAttr.label, cloneDeep(COMPUTED_DEFAULT_LABEL.value))
|
||||||
|
//初始化format单位语言
|
||||||
|
initFormatCfgUnit(state.labelForm.labelFormatter)
|
||||||
|
initFormatCfgUnit(state.labelForm.quotaLabelFormatter)
|
||||||
|
initFormatCfgUnit(state.labelForm.totalFormatter)
|
||||||
if (chartType.value === 'liquid' && state.labelForm.fontSize < fontSizeList.value[0].value) {
|
if (chartType.value === 'liquid' && state.labelForm.fontSize < fontSizeList.value[0].value) {
|
||||||
state.labelForm.fontSize = fontSizeList.value[0].value
|
state.labelForm.fontSize = fontSizeList.value[0].value
|
||||||
}
|
}
|
||||||
@ -486,6 +502,7 @@ const isProgressBar = computed(() => {
|
|||||||
:disabled="!state.labelForm.show"
|
:disabled="!state.labelForm.show"
|
||||||
:model="state.labelForm"
|
:model="state.labelForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-row v-show="showEmpty" style="margin-bottom: 12px">
|
<el-row v-show="showEmpty" style="margin-bottom: 12px">
|
||||||
{{ t('chart.no_other_configurable_properties') }}</el-row
|
{{ t('chart.no_other_configurable_properties') }}</el-row
|
||||||
@ -738,11 +755,31 @@ const isProgressBar = computed(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="state.labelForm.labelFormatter && state.labelForm.labelFormatter.type !== 'percent'"
|
v-if="state.labelForm.labelFormatter && state.labelForm.labelFormatter.type !== 'percent'"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.labelForm.labelFormatter.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v => changeLabelUnitLanguage(state.labelForm.labelFormatter, v, 'labelFormatter')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_unit')"
|
:label="$t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -753,18 +790,20 @@ const isProgressBar = computed(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.labelForm.labelFormatter.unit"
|
v-model="state.labelForm.labelFormatter.unit"
|
||||||
:placeholder="$t('chart.pls_select_field')"
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
@change="changeLabelAttr('labelFormatter.unit')"
|
@change="changeLabelAttr('labelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(state.labelForm.labelFormatter.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="$t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_suffix')"
|
:label="$t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -780,6 +819,7 @@ const isProgressBar = computed(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -871,11 +911,32 @@ const isProgressBar = computed(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="state.labelForm.totalFormatter && state.labelForm.totalFormatter.type !== 'percent'"
|
v-if="state.labelForm.totalFormatter && state.labelForm.totalFormatter.type !== 'percent'"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.labelForm.totalFormatter.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeLabelUnitLanguage(state.labelForm.totalFormatter, v, 'totalFormatter')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_unit')"
|
:label="$t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -886,18 +947,20 @@ const isProgressBar = computed(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.labelForm.totalFormatter.unit"
|
v-model="state.labelForm.totalFormatter.unit"
|
||||||
:placeholder="$t('chart.pls_select_field')"
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
@change="changeLabelAttr('totalFormatter.unit')"
|
@change="changeLabelAttr('totalFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(state.labelForm.totalFormatter.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="$t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_suffix')"
|
:label="$t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -913,6 +976,7 @@ const isProgressBar = computed(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -1001,14 +1065,40 @@ const isProgressBar = computed(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="
|
v-if="
|
||||||
state.labelForm.quotaLabelFormatter &&
|
state.labelForm.quotaLabelFormatter &&
|
||||||
state.labelForm.quotaLabelFormatter.type !== 'percent'
|
state.labelForm.quotaLabelFormatter.type !== 'percent'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
:disabled="!state.labelForm.showQuota"
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.labelForm.quotaLabelFormatter.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeLabelUnitLanguage(
|
||||||
|
state.labelForm.quotaLabelFormatter,
|
||||||
|
v,
|
||||||
|
'quotaLabelFormatter'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_unit')"
|
:label="t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1020,18 +1110,22 @@ const isProgressBar = computed(() => {
|
|||||||
v-model="state.labelForm.quotaLabelFormatter.unit"
|
v-model="state.labelForm.quotaLabelFormatter.unit"
|
||||||
:placeholder="t('chart.pls_select_field')"
|
:placeholder="t('chart.pls_select_field')"
|
||||||
size="small"
|
size="small"
|
||||||
@change="changeLabelAttr('quotaLabelFormatter.unit')"
|
@change="changeLabelAttr('quotaLabelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(
|
||||||
|
state.labelForm.quotaLabelFormatter.unitLanguage
|
||||||
|
)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_suffix')"
|
:label="t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1049,6 +1143,7 @@ const isProgressBar = computed(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -1267,15 +1362,41 @@ const isProgressBar = computed(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="
|
v-if="
|
||||||
curSeriesFormatter.show &&
|
curSeriesFormatter.show &&
|
||||||
curSeriesFormatter.formatterCfg &&
|
curSeriesFormatter.formatterCfg &&
|
||||||
curSeriesFormatter.formatterCfg.type !== 'percent'
|
curSeriesFormatter.formatterCfg.type !== 'percent'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
:disabled="!curSeriesFormatter.show"
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="curSeriesFormatter.formatterCfg.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeLabelUnitLanguage(
|
||||||
|
curSeriesFormatter.formatterCfg,
|
||||||
|
v,
|
||||||
|
'seriesLabelFormatter'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_unit')"
|
:label="t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1290,15 +1411,17 @@ const isProgressBar = computed(() => {
|
|||||||
@change="changeLabelAttr('seriesLabelFormatter')"
|
@change="changeLabelAttr('seriesLabelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(curSeriesFormatter.formatterCfg.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_suffix')"
|
:label="t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1316,6 +1439,7 @@ const isProgressBar = computed(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -1478,11 +1602,33 @@ const isProgressBar = computed(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="state.labelForm.labelFormatter && state.labelForm.labelFormatter.type !== 'percent'"
|
v-if="state.labelForm.labelFormatter && state.labelForm.labelFormatter.type !== 'percent'"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
:disabled="!state.labelForm.childrenShow"
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.labelForm.labelFormatter.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeLabelUnitLanguage(state.labelForm.labelFormatter, v, 'labelFormatter')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_unit')"
|
:label="$t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1494,18 +1640,20 @@ const isProgressBar = computed(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.labelForm.labelFormatter.unit"
|
v-model="state.labelForm.labelFormatter.unit"
|
||||||
:placeholder="$t('chart.pls_select_field')"
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
@change="changeLabelAttr('labelFormatter.unit')"
|
@change="changeLabelAttr('labelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(state.labelForm.labelFormatter.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="$t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_suffix')"
|
:label="$t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1522,6 +1670,7 @@ const isProgressBar = computed(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -1711,11 +1860,33 @@ const isProgressBar = computed(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="state.labelForm.labelFormatter && state.labelForm.labelFormatter.type !== 'percent'"
|
v-if="state.labelForm.labelFormatter && state.labelForm.labelFormatter.type !== 'percent'"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
:disabled="!state.labelForm.childrenShow"
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.labelForm.labelFormatter.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeLabelUnitLanguage(state.labelForm.labelFormatter, v, 'labelFormatter')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_unit')"
|
:label="$t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1727,18 +1898,21 @@ const isProgressBar = computed(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.labelForm.labelFormatter.unit"
|
v-model="state.labelForm.labelFormatter.unit"
|
||||||
:placeholder="$t('chart.pls_select_field')"
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
@change="changeLabelAttr('labelFormatter.unit')"
|
@change="changeLabelAttr('labelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(state.labelForm.labelFormatter.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="$t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="$t('chart.value_formatter_suffix')"
|
:label="$t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -1755,6 +1929,7 @@ const isProgressBar = computed(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -1850,9 +2025,8 @@ const isProgressBar = computed(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.series-select {
|
.series-select {
|
||||||
:deep(.ed-select__prefix--light) {
|
:deep(.ed-select__prefix::after) {
|
||||||
padding-right: unset;
|
display: none;
|
||||||
border-right: unset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ed-select__prefix--dark) {
|
:deep(.ed-select__prefix--dark) {
|
||||||
|
@ -5,17 +5,18 @@ import icon_rightAlign_outlined from '@/assets/svg/icon_right-align_outlined.svg
|
|||||||
import icon_topAlign_outlined from '@/assets/svg/icon_top-align_outlined.svg'
|
import icon_topAlign_outlined from '@/assets/svg/icon_top-align_outlined.svg'
|
||||||
import icon_verticalAlign_outlined from '@/assets/svg/icon_vertical-align_outlined.svg'
|
import icon_verticalAlign_outlined from '@/assets/svg/icon_vertical-align_outlined.svg'
|
||||||
import icon_bottomAlign_outlined from '@/assets/svg/icon_bottom-align_outlined.svg'
|
import icon_bottomAlign_outlined from '@/assets/svg/icon_bottom-align_outlined.svg'
|
||||||
import { computed, onMounted, reactive, watch } from 'vue'
|
import { computed, onMounted, reactive, watch, ref } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import {
|
import {
|
||||||
COLOR_PANEL,
|
COLOR_PANEL,
|
||||||
DEFAULT_LEGEND_STYLE,
|
DEFAULT_LEGEND_STYLE,
|
||||||
DEFAULT_MISC
|
DEFAULT_MISC
|
||||||
} from '@/views/chart/components/editor/util/chart'
|
} from '@/views/chart/components/editor/util/chart'
|
||||||
import { ElCol, ElRow, ElSpace } from 'element-plus-secondary'
|
import { ElCol, ElFormItem, ElRow, ElSpace } from 'element-plus-secondary'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||||
import { getDynamicColorScale } from '@/views/chart/components/js/util'
|
import { getDynamicColorScale } from '@/views/chart/components/js/util'
|
||||||
|
import CustomSortEdit from '@/views/chart/components/editor/drag-item/components/CustomSortEdit.vue'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ useEmitt({
|
|||||||
})
|
})
|
||||||
const emit = defineEmits(['onLegendChange', 'onMiscChange'])
|
const emit = defineEmits(['onLegendChange', 'onMiscChange'])
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
watch(
|
watch(
|
||||||
() => props.chart.customStyle,
|
() => props.chart.customStyle,
|
||||||
@ -55,7 +56,9 @@ const state = reactive({
|
|||||||
legendForm: {
|
legendForm: {
|
||||||
...JSON.parse(JSON.stringify(DEFAULT_LEGEND_STYLE)),
|
...JSON.parse(JSON.stringify(DEFAULT_LEGEND_STYLE)),
|
||||||
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr
|
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr
|
||||||
}
|
},
|
||||||
|
showCustomSort: false,
|
||||||
|
customSortField: null
|
||||||
})
|
})
|
||||||
|
|
||||||
const chartType = computed(() => {
|
const chartType = computed(() => {
|
||||||
@ -99,7 +102,9 @@ const changeMisc = prop => {
|
|||||||
emit('onMiscChange', { data: state.legendForm.miscForm, requestData: true }, prop)
|
emit('onMiscChange', { data: state.legendForm.miscForm, requestData: true }, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const legendSort = ref()
|
||||||
const init = () => {
|
const init = () => {
|
||||||
|
legendSort.value?.blur()
|
||||||
const chart = JSON.parse(JSON.stringify(props.chart))
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
if (chart.customStyle) {
|
if (chart.customStyle) {
|
||||||
let customStyle = null
|
let customStyle = null
|
||||||
@ -226,6 +231,31 @@ const getMapCustomRange = index => {
|
|||||||
if (index === state.legendForm.miscForm.mapLegendNumber) return t('chart.max')
|
if (index === state.legendForm.miscForm.mapLegendNumber) return t('chart.max')
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
const customSort = []
|
||||||
|
const changeLegendSort = sort => {
|
||||||
|
if (sort === 'custom') {
|
||||||
|
state.customSortField = cloneDeep(props.chart.xAxisExt?.[0])
|
||||||
|
if (!state.customSortField) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
state.showCustomSort = true
|
||||||
|
} else {
|
||||||
|
state.showCustomSort = false
|
||||||
|
state.legendForm.sort = sort
|
||||||
|
}
|
||||||
|
changeLegendStyle('sort')
|
||||||
|
}
|
||||||
|
const closeCustomSort = () => {
|
||||||
|
state.showCustomSort = false
|
||||||
|
}
|
||||||
|
const saveCustomSort = () => {
|
||||||
|
state.showCustomSort = false
|
||||||
|
state.legendForm.customSort = customSort
|
||||||
|
changeLegendStyle('customSort')
|
||||||
|
}
|
||||||
|
const customSortChange = list => {
|
||||||
|
customSort.splice(0, customSort.length, ...list)
|
||||||
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init()
|
init()
|
||||||
})
|
})
|
||||||
@ -237,6 +267,7 @@ onMounted(() => {
|
|||||||
:disabled="!state.legendForm.show"
|
:disabled="!state.legendForm.show"
|
||||||
:model="state.legendForm"
|
:model="state.legendForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-row :gutter="8">
|
<el-row :gutter="8">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
@ -281,7 +312,51 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-form-item v-if="showProperty('showRange')" class="form-item" :class="'form-item-' + themes">
|
||||||
|
<el-checkbox
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.legendForm.showRange"
|
||||||
|
@change="changeLegendStyle('showRange')"
|
||||||
|
:label="t('chart.show_range_bg')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<div
|
||||||
|
style="flex: 1; display: flex"
|
||||||
|
v-if="showProperty('showRange') && state.legendForm.showRange"
|
||||||
|
>
|
||||||
|
<el-form-item :label="t('chart.icon')" class="form-item" :class="'form-item-' + themes">
|
||||||
|
<el-select
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.legendForm.miscForm.bullet.bar.ranges.symbol"
|
||||||
|
:placeholder="t('chart.icon')"
|
||||||
|
@change="changeMisc('bullet.bar.ranges.symbol')"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in iconSymbolOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 8px">
|
||||||
|
<template #label> </template>
|
||||||
|
<el-select
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.legendForm.miscForm.bullet.bar.ranges.symbolSize"
|
||||||
|
size="small"
|
||||||
|
@change="changeMisc('bullet.bar.ranges.symbolSize')"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="option in sizeList"
|
||||||
|
:key="option.value"
|
||||||
|
:label="option.name"
|
||||||
|
:value="option.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
<el-space>
|
<el-space>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -633,7 +708,55 @@ onMounted(() => {
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-space>
|
</el-space>
|
||||||
|
<el-form-item
|
||||||
|
class="form-item"
|
||||||
|
v-if="showProperty('legendSort')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
:label="t('chart.legend_sort')"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
v-model="state.legendForm.sort"
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
:disabled="!chart.xAxisExt?.length"
|
||||||
|
ref="legendSort"
|
||||||
|
@change="changeLegendSort"
|
||||||
|
>
|
||||||
|
<el-option :label="t('chart.none')" value="none" />
|
||||||
|
<el-option :label="t('chart.asc')" value="asc" />
|
||||||
|
<el-option :label="t('chart.desc')" value="desc" />
|
||||||
|
<el-option
|
||||||
|
value="custom"
|
||||||
|
:label="t('visualization.custom_sort')"
|
||||||
|
@click="changeLegendSort('custom')"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
<el-dialog
|
||||||
|
v-if="state.showCustomSort"
|
||||||
|
v-model="state.showCustomSort"
|
||||||
|
:title="t('chart.custom_sort') + t('chart.sort')"
|
||||||
|
:visible="state.showCustomSort"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
destroy-on-close
|
||||||
|
width="372px"
|
||||||
|
class="dialog-css custom_sort_dialog"
|
||||||
|
>
|
||||||
|
<custom-sort-edit
|
||||||
|
field-type="xAxisExt"
|
||||||
|
:chart="chart"
|
||||||
|
:field="state.customSortField"
|
||||||
|
:origin-sort-list="state.legendForm.customSort"
|
||||||
|
@on-sort-change="customSortChange"
|
||||||
|
/>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="closeCustomSort">{{ t('chart.cancel') }} </el-button>
|
||||||
|
<el-button type="primary" @click="saveCustomSort">{{ t('chart.confirm') }} </el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -5,7 +5,7 @@ import { useI18n } from '@/hooks/web/useI18n'
|
|||||||
import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
||||||
import { ElRow } from 'element-plus-secondary'
|
import { ElRow } from 'element-plus-secondary'
|
||||||
import { fieldType } from '@/utils/attr'
|
import { fieldType } from '@/utils/attr'
|
||||||
import { cloneDeep, defaultsDeep, isEmpty } from 'lodash-es'
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||||
import { iconFieldMap } from '@/components/icon-group/field-list'
|
import { iconFieldMap } from '@/components/icon-group/field-list'
|
||||||
|
|
||||||
@ -27,13 +27,42 @@ useEmitt({
|
|||||||
callback: args => wordCloudDefaultDataRange(args)
|
callback: args => wordCloudDefaultDataRange(args)
|
||||||
})
|
})
|
||||||
useEmitt({
|
useEmitt({
|
||||||
name: 'gauge-default-data',
|
name: 'gauge-liquid-y-value',
|
||||||
callback: args => gaugeOrLiquidDefaultRangeData(args)
|
callback: args => gaugeLiquidYaxisValue(args)
|
||||||
})
|
})
|
||||||
useEmitt({
|
useEmitt({
|
||||||
name: 'liquid-default-data',
|
name: 'chart-type-change',
|
||||||
callback: args => gaugeOrLiquidDefaultRangeData(args)
|
callback: () => {
|
||||||
|
if (isLiquid.value || isGauge.value) {
|
||||||
|
init()
|
||||||
|
initField()
|
||||||
|
initAxis(props.chart.yAxis[0]?.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
const addAxis = (form: AxisEditForm) => {
|
||||||
|
initAxis(form.axis[0]?.id)
|
||||||
|
}
|
||||||
|
useEmitt({ name: 'addAxis', callback: addAxis })
|
||||||
|
const wordCloudDefaultDataRange = ({ data: { max, min } }) => {
|
||||||
|
Object.assign(state.miscForm.wordCloudAxisValueRange, {
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
fieldId: props.chart.yAxis?.[0]?.id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const gaugeLiquidYaxisDefaultValue = { gaugeMax: undefined, liquidMax: undefined }
|
||||||
|
const gaugeLiquidYaxisValue = args => {
|
||||||
|
const { type, max } = args.data
|
||||||
|
const key = type === 'gauge' ? 'gaugeMax' : type === 'liquid' ? 'liquidMax' : null
|
||||||
|
if (key) {
|
||||||
|
gaugeLiquidYaxisDefaultValue[key] = cloneDeep(max)
|
||||||
|
if (!state.miscForm[key]) {
|
||||||
|
state.miscForm[key] = gaugeLiquidYaxisDefaultValue[key]
|
||||||
|
changeMisc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
const emit = defineEmits(['onMiscChange'])
|
const emit = defineEmits(['onMiscChange'])
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@ -46,24 +75,21 @@ watch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const validLiquidMaxField = computed(() => {
|
const validLiquidMaxField = computed(() => {
|
||||||
return isValidField(state.liquidMaxField)
|
return isValidField(state.miscForm.liquidMaxField)
|
||||||
})
|
})
|
||||||
const validMinField = computed(() => {
|
const validMinField = computed(() => {
|
||||||
return isValidField(state.minField)
|
return isValidField(state.miscForm.gaugeMinField)
|
||||||
})
|
})
|
||||||
const validMaxField = computed(() => {
|
const validMaxField = computed(() => {
|
||||||
return isValidField(state.maxField)
|
return isValidField(state.miscForm.gaugeMaxField)
|
||||||
})
|
})
|
||||||
|
const isValidField = field => {
|
||||||
|
return field.id !== '-1' && quotaData.value.findIndex(ele => ele.id === field.id) !== -1
|
||||||
|
}
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)),
|
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)),
|
||||||
minField: {},
|
quotaData: []
|
||||||
maxField: {},
|
|
||||||
liquidMaxField: {},
|
|
||||||
quotaData: [],
|
|
||||||
// 是否已处理没有 y 轴字段的情况
|
|
||||||
liquidProcessedNoYAxis: false,
|
|
||||||
gaugeProcessedNoYAxis: false
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const liquidShapeOptions = [
|
const liquidShapeOptions = [
|
||||||
@ -81,12 +107,6 @@ const changeMisc = (prop = '', refresh = false) => {
|
|||||||
const init = () => {
|
const init = () => {
|
||||||
const misc = cloneDeep(props.chart.customAttr.misc)
|
const misc = cloneDeep(props.chart.customAttr.misc)
|
||||||
state.miscForm = defaultsDeep(misc, cloneDeep(DEFAULT_MISC)) as ChartMiscAttr
|
state.miscForm = defaultsDeep(misc, cloneDeep(DEFAULT_MISC)) as ChartMiscAttr
|
||||||
const maxTypeKey = props.chart.type === 'liquid' ? 'liquidMaxType' : 'gaugeMaxType'
|
|
||||||
const maxValueKey = props.chart.type === 'liquid' ? 'liquidMax' : 'gaugeMax'
|
|
||||||
if (!props.chart.yAxis.length) {
|
|
||||||
state.miscForm[maxTypeKey] = 'fix'
|
|
||||||
state.miscForm[maxValueKey] = undefined
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initField = () => {
|
const initField = () => {
|
||||||
@ -95,96 +115,57 @@ const initField = () => {
|
|||||||
if (!yAxisInDataset) {
|
if (!yAxisInDataset) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 过滤掉记录数字段以及计算字段
|
// 过滤掉记录数字段
|
||||||
state.quotaData = props.quotaFields.filter(ele => ele.id !== '-1' && ele.extField !== 2)
|
state.quotaData = props.quotaFields.filter(ele => ele.id !== '-1')
|
||||||
if (!isEmpty(state.miscForm.gaugeMinField.id)) {
|
|
||||||
state.minField = getQuotaField(state.miscForm.gaugeMinField.id)
|
|
||||||
}
|
|
||||||
if (!isEmpty(state.miscForm.gaugeMaxField.id)) {
|
|
||||||
state.maxField = getQuotaField(state.miscForm.gaugeMaxField.id)
|
|
||||||
}
|
|
||||||
if (!isEmpty(state.miscForm.liquidMaxField.id)) {
|
|
||||||
state.liquidMaxField = getQuotaField(state.miscForm.liquidMaxField.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const COUNT_DE_TYPE = [0, 1, 5]
|
|
||||||
const NUMBER_DE_TYPE = [1, 2, 3]
|
|
||||||
const getFieldSummaryByDeType = (deType: number) => {
|
|
||||||
return COUNT_DE_TYPE.includes(deType) || !deType ? 'count' : 'sum'
|
|
||||||
}
|
}
|
||||||
|
const NUMBER_DE_TYPE = [2, 3]
|
||||||
|
|
||||||
const getDynamicFieldId = () => {
|
const getDynamicField = () => {
|
||||||
// 返回yAxis字段ID
|
return (
|
||||||
const curFieldObj = quotaData.value?.find(item => item.id === props.chart.yAxis?.[0]?.id)
|
quotaData.value?.find(item => item.id === props.chart.yAxis?.[0]?.id) || quotaData.value?.[0]
|
||||||
if (curFieldObj) return curFieldObj.id
|
)
|
||||||
// 返回第一个数字类型字段ID
|
|
||||||
return quotaData.value?.filter(item => NUMBER_DE_TYPE.includes(item.deType))?.[0]?.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeQuotaField = (type: string, resetSummary?: boolean) => {
|
const changeQuotaField = (type: string, resetSummary?: boolean) => {
|
||||||
if (isGauge.value) {
|
if (isGauge.value) {
|
||||||
if (type === 'max') {
|
if (type === 'max') {
|
||||||
|
const quotaField = getQuotaField(state.miscForm.gaugeMaxField.id || getDynamicField()?.id)
|
||||||
|
state.miscForm.gaugeMaxField.id = quotaField.id
|
||||||
const isDynamic = state.miscForm.gaugeMaxType === 'dynamic'
|
const isDynamic = state.miscForm.gaugeMaxType === 'dynamic'
|
||||||
if (isDynamic) {
|
if (isDynamic && resetSummary) {
|
||||||
if (!state.miscForm.gaugeMaxField.id) {
|
state.miscForm.gaugeMaxField.summary = quotaField.summary
|
||||||
setDynamicFieldId(state.miscForm.gaugeMaxField)
|
|
||||||
}
|
}
|
||||||
if (!state.miscForm.gaugeMaxField.summary || resetSummary) {
|
if (!isDynamic) {
|
||||||
state.miscForm.gaugeMaxField.summary = 'sum'
|
state.miscForm.gaugeMax = cloneDeep(gaugeLiquidYaxisDefaultValue.gaugeMax)
|
||||||
}
|
state.miscForm.gaugeMaxField.id = ''
|
||||||
if (state.miscForm.gaugeMaxField.id && state.miscForm.gaugeMaxField.summary) {
|
|
||||||
state.maxField = getQuotaField(state.miscForm.gaugeMaxField.id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.miscForm.gaugeMax = state.miscForm.gaugeMax || cloneDeep(defaultMaxValue.gaugeMax)
|
|
||||||
}
|
}
|
||||||
changeMisc('gaugeMaxField', true)
|
changeMisc('gaugeMaxField', true)
|
||||||
}
|
}
|
||||||
if (type === 'min') {
|
if (type === 'min') {
|
||||||
|
const quotaField = getQuotaField(state.miscForm.gaugeMinField.id || getDynamicField()?.id)
|
||||||
|
state.miscForm.gaugeMinField.id = quotaField.id
|
||||||
const isDynamic = state.miscForm.gaugeMinType === 'dynamic'
|
const isDynamic = state.miscForm.gaugeMinType === 'dynamic'
|
||||||
if (isDynamic) {
|
if (isDynamic && resetSummary) {
|
||||||
if (!state.miscForm.gaugeMinField.id) {
|
state.miscForm.gaugeMinField.summary = quotaField.summary
|
||||||
setDynamicFieldId(state.miscForm.gaugeMinField)
|
|
||||||
}
|
}
|
||||||
if (!state.miscForm.gaugeMinField.summary || resetSummary) {
|
if (!isDynamic) {
|
||||||
state.miscForm.gaugeMinField.summary = 'sum'
|
state.miscForm.gaugeMin = state.miscForm.gaugeMin || 0
|
||||||
}
|
state.miscForm.gaugeMinField.id = ''
|
||||||
if (state.miscForm.gaugeMinField.id && state.miscForm.gaugeMinField.summary) {
|
|
||||||
state.minField = getQuotaField(state.miscForm.gaugeMinField.id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state.miscForm.gaugeMin = state.miscForm.gaugeMin ?? 0
|
|
||||||
}
|
}
|
||||||
changeMisc('gaugeMinField', true)
|
changeMisc('gaugeMinField', true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isLiquid.value) {
|
if (isLiquid.value) {
|
||||||
const field = state.miscForm.liquidMaxField
|
const quotaField = getQuotaField(state.miscForm.liquidMaxField.id || getDynamicField()?.id)
|
||||||
const maxValueKey = 'liquidMax'
|
state.miscForm.liquidMaxField.id = quotaField.id
|
||||||
const isDynamic = state.miscForm.liquidMaxType === 'dynamic'
|
const isDynamic = state.miscForm.liquidMaxType === 'dynamic'
|
||||||
if (isDynamic) {
|
if (isDynamic && resetSummary) {
|
||||||
if (!field.id) setDynamicFieldId(field)
|
state.miscForm.liquidMaxField.summary = quotaField.summary
|
||||||
if (!field.summary || resetSummary) field.summary = 'count'
|
|
||||||
if (field.id && field.summary) {
|
|
||||||
state.liquidMaxField = getQuotaField(field.id)
|
|
||||||
}
|
}
|
||||||
} else {
|
if (!isDynamic) {
|
||||||
state.miscForm.liquidMax = state.miscForm.liquidMax || cloneDeep(defaultMaxValue.liquidMax)
|
state.miscForm.liquidMax = cloneDeep(gaugeLiquidYaxisDefaultValue.liquidMax)
|
||||||
|
state.miscForm.liquidMaxField.id = ''
|
||||||
}
|
}
|
||||||
changeMisc(`${maxValueKey}Field`, true)
|
changeMisc('liquidMaxField', true)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setDynamicFieldId = fieldObj => {
|
|
||||||
const yAxisField = props.chart.yAxis?.[0]
|
|
||||||
if (
|
|
||||||
yAxisField?.extField === 2 ||
|
|
||||||
yAxisField?.id === '-1' ||
|
|
||||||
!NUMBER_DE_TYPE.includes(yAxisField?.deType)
|
|
||||||
) {
|
|
||||||
fieldObj.id = getDynamicFieldId()
|
|
||||||
} else {
|
|
||||||
fieldObj.id = yAxisField?.id
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,222 +173,139 @@ const getQuotaField = id => {
|
|||||||
return quotaData.value.find(ele => ele.id === id) || {}
|
return quotaData.value.find(ele => ele.id === id) || {}
|
||||||
}
|
}
|
||||||
|
|
||||||
const isValidField = field => {
|
|
||||||
return field.id !== '-1' && quotaData.value.findIndex(ele => ele.id === field.id) !== -1
|
|
||||||
}
|
|
||||||
|
|
||||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
const showProperty = prop => props.propertyInner?.includes(prop)
|
||||||
const wordCloudDefaultDataRange = args => {
|
|
||||||
state.miscForm.wordCloudAxisValueRange.max = args.data.max
|
|
||||||
state.miscForm.wordCloudAxisValueRange.min = args.data.min
|
|
||||||
state.miscForm.wordCloudAxisValueRange.fieldId = props.chart.yAxis?.[0]?.id
|
|
||||||
}
|
|
||||||
const defaultMaxValue = {
|
|
||||||
gaugeMax: undefined,
|
|
||||||
liquidMax: undefined
|
|
||||||
}
|
|
||||||
const gaugeOrLiquidDefaultRangeData = args => {
|
|
||||||
if (args.data.type === 'gauge') {
|
|
||||||
defaultMaxValue.gaugeMax = cloneDeep(args.data.max)
|
|
||||||
if (!state.miscForm.gaugeMax) {
|
|
||||||
state.miscForm.gaugeMax = cloneDeep(defaultMaxValue.gaugeMax)
|
|
||||||
changeMisc('gaugeMaxField', true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (args.data.type === 'liquid') {
|
|
||||||
defaultMaxValue.liquidMax = cloneDeep(args.data.max)
|
|
||||||
if (!state.miscForm.liquidMax) {
|
|
||||||
state.miscForm.liquidMax = cloneDeep(defaultMaxValue.liquidMax)
|
|
||||||
changeMisc('liquidMaxField', true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 校验最大值的输入
|
* 校验最大值的输入
|
||||||
*/
|
*/
|
||||||
const changeMaxValidate = prop => {
|
const changeFixedValidate = prop => {
|
||||||
if (prop === 'gaugeMax' && !state.miscForm.gaugeMax) {
|
if (prop === 'gaugeMax' && !state.miscForm.gaugeMax) {
|
||||||
state.miscForm.gaugeMax = cloneDeep(defaultMaxValue.gaugeMax)
|
state.miscForm.gaugeMax = cloneDeep(gaugeLiquidYaxisDefaultValue.gaugeMax)
|
||||||
}
|
}
|
||||||
if (prop === 'liquidMax' && !state.miscForm.liquidMax) {
|
if (prop === 'liquidMax' && !state.miscForm.liquidMax) {
|
||||||
state.miscForm.liquidMax = cloneDeep(defaultMaxValue.liquidMax)
|
state.miscForm.liquidMax = cloneDeep(gaugeLiquidYaxisDefaultValue.liquidMax)
|
||||||
|
}
|
||||||
|
if (prop === 'gaugeMin' && !state.miscForm.gaugeMin) {
|
||||||
|
state.miscForm.gaugeMin = 0
|
||||||
}
|
}
|
||||||
changeMisc(prop, true)
|
changeMisc(prop, true)
|
||||||
}
|
}
|
||||||
const addAxis = (form: AxisEditForm) => {
|
|
||||||
initAxis(form.axis[0]?.id)
|
|
||||||
}
|
|
||||||
const initAxis = yAxisId => {
|
const initAxis = yAxisId => {
|
||||||
state.quotaData = []
|
state.quotaData = []
|
||||||
if (yAxisId) {
|
if (yAxisId) {
|
||||||
const uniqueIds = new Set(state.quotaData.map(item => item.id))
|
const uniqueIds = new Set(state.quotaData.map(item => item.id))
|
||||||
state.quotaData = [
|
state.quotaData = [
|
||||||
...props.quotaFields.filter(
|
...props.quotaFields.filter(ele => ele.id !== '-1' && !uniqueIds.has(ele.id))
|
||||||
ele => ele.id !== '-1' && ele.extField !== 2 && !uniqueIds.has(ele.id)
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
const maxTypeKey = isLiquid.value ? 'liquidMaxType' : 'gaugeMaxType'
|
|
||||||
const maxValueKey = isLiquid.value ? 'liquidMax' : 'gaugeMax'
|
|
||||||
if (state.quotaData.length) {
|
if (state.quotaData.length) {
|
||||||
if (isLiquid.value) {
|
if (isLiquid.value) {
|
||||||
state.miscForm[maxTypeKey] = 'dynamic'
|
state.miscForm.liquidMaxType = 'dynamic'
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = getDynamicFieldId() ?? state.quotaData[0]?.id
|
state.miscForm.liquidMaxField.id = getDynamicField()?.id || state.quotaData[0]?.id
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = 'sum'
|
const quotaField = getQuotaField(state.miscForm.liquidMaxField.id)
|
||||||
state.liquidMaxField = getQuotaField(state.miscForm[maxValueKey + 'Field']['id'])
|
state.miscForm.liquidMaxField.summary = quotaField.summary
|
||||||
changeMisc(`${maxValueKey}Field`, true)
|
|
||||||
}
|
}
|
||||||
if (isGauge.value) {
|
if (isGauge.value) {
|
||||||
// max
|
// max
|
||||||
state.miscForm[maxTypeKey] = 'dynamic'
|
state.miscForm.gaugeMaxType = 'dynamic'
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = getDynamicFieldId() ?? state.quotaData[0]?.id
|
state.miscForm.gaugeMaxField.id = getDynamicField()?.id || state.quotaData[0]?.id
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = 'sum'
|
const quotaField = getQuotaField(state.miscForm.gaugeMaxField.id)
|
||||||
state.maxField = getQuotaField(state.miscForm[maxValueKey + 'Field']['id'])
|
state.miscForm.gaugeMaxField.summary = quotaField.summary
|
||||||
changeMisc(`${maxValueKey}Field`, true)
|
|
||||||
// min
|
// min
|
||||||
state.miscForm.gaugeMinType = 'fix'
|
state.miscForm.gaugeMinType = 'fix'
|
||||||
state.miscForm.gaugeMin = 0
|
state.miscForm.gaugeMin = 0
|
||||||
changeMisc('gaugeMinField', true)
|
state.miscForm.gaugeMinField.summary = quotaField.summary
|
||||||
}
|
}
|
||||||
|
changeMisc()
|
||||||
} else {
|
} else {
|
||||||
if (isLiquid.value) {
|
if (isLiquid.value) {
|
||||||
state.miscForm[maxTypeKey] = 'fix'
|
state.miscForm.liquidMaxType = 'fix'
|
||||||
state.miscForm[maxValueKey] = cloneDeep(defaultMaxValue[maxValueKey]) ?? 0
|
state.miscForm.liquidMax = cloneDeep(gaugeLiquidYaxisDefaultValue.liquidMax) || 0
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = ''
|
state.miscForm.liquidMaxField.id = ''
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = ''
|
state.miscForm.liquidMaxField.summary = ''
|
||||||
|
changeMisc('liquidMax', true)
|
||||||
}
|
}
|
||||||
if (isGauge.value) {
|
if (isGauge.value) {
|
||||||
// max
|
// max
|
||||||
state.miscForm[maxTypeKey] = 'fix'
|
state.miscForm.gaugeMaxType = 'fix'
|
||||||
state.miscForm[maxValueKey] = cloneDeep(defaultMaxValue[maxValueKey]) ?? 0
|
state.miscForm.gaugeMax = gaugeLiquidYaxisDefaultValue.gaugeMax || 0
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = ''
|
state.miscForm.liquidMaxField.id = ''
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = ''
|
state.miscForm.liquidMaxField.summary = ''
|
||||||
|
changeMisc('gaugeMax', true)
|
||||||
// min
|
// min
|
||||||
state.miscForm.gaugeMinType = 'fix'
|
state.miscForm.gaugeMinType = 'fix'
|
||||||
state.miscForm.gaugeMin = 0
|
state.miscForm.gaugeMin = 0
|
||||||
state.miscForm.gaugeMinField.id = ''
|
state.miscForm.gaugeMinField.id = ''
|
||||||
state.miscForm.gaugeMinField.summary = ''
|
state.miscForm.gaugeMinField.summary = ''
|
||||||
}
|
changeMisc('gaugeMin', true)
|
||||||
changeMisc('', false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const initStateForm = () => {
|
|
||||||
state.quotaData = []
|
|
||||||
if (props.chart.yAxis?.[0]?.id) {
|
|
||||||
const uniqueIds = new Set(state.quotaData.map(item => item.id))
|
|
||||||
state.quotaData = [
|
|
||||||
...props.quotaFields.filter(
|
|
||||||
ele => ele.id !== '-1' && ele.extField !== 2 && !uniqueIds.has(ele.id)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
const maxTypeKey = isLiquid.value ? 'liquidMaxType' : 'gaugeMaxType'
|
|
||||||
const maxValueKey = isLiquid.value ? 'liquidMax' : 'gaugeMax'
|
|
||||||
if (quotaData.value.length) {
|
|
||||||
if (isLiquid.value) {
|
|
||||||
const hasDynamicValue = props.quotaFields.find(
|
|
||||||
ele => ele.id === state.miscForm[maxValueKey + 'Field']['id']
|
|
||||||
)
|
|
||||||
const hasFixValue = state.miscForm[maxValueKey]
|
|
||||||
if (state.miscForm[maxTypeKey] === 'dynamic' && !hasDynamicValue) {
|
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = state.quotaData[0]?.id ?? ''
|
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = 'sum'
|
|
||||||
state.liquidMaxField = getQuotaField(state.miscForm[maxValueKey + 'Field']['id'])
|
|
||||||
changeMisc(`${maxValueKey}Field`, true)
|
|
||||||
} else if (state.miscForm[maxTypeKey] === 'fix' && !hasFixValue && hasFixValue !== 0) {
|
|
||||||
state.miscForm[maxValueKey] = cloneDeep(defaultMaxValue[maxValueKey]) ?? 0
|
|
||||||
changeMisc(`${maxValueKey}Field`, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isGauge.value) {
|
|
||||||
// max
|
|
||||||
const hasDynamicValue = props.quotaFields.find(
|
|
||||||
ele => ele.id === state.miscForm[maxValueKey + 'Field']['id']
|
|
||||||
)
|
|
||||||
const hasFixValue = state.miscForm[maxValueKey]
|
|
||||||
if (state.miscForm[maxTypeKey] === 'dynamic' && !hasDynamicValue) {
|
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = state.quotaData[0]?.id ?? ''
|
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = 'sum'
|
|
||||||
state.maxField = getQuotaField(state.miscForm[maxValueKey + 'Field']['id'])
|
|
||||||
changeMisc(`${maxValueKey}Field`, true)
|
|
||||||
} else if (state.miscForm[maxTypeKey] === 'fix' && !hasFixValue && hasFixValue !== 0) {
|
|
||||||
state.miscForm[maxValueKey] = cloneDeep(defaultMaxValue[maxValueKey]) ?? 0
|
|
||||||
changeMisc(`${maxValueKey}Field`, true)
|
|
||||||
}
|
|
||||||
// min
|
|
||||||
const hasDynamicMinValue = props.quotaFields.find(
|
|
||||||
ele => ele.id === state.miscForm.gaugeMinField.id
|
|
||||||
)
|
|
||||||
if (state.miscForm.gaugeMinType === 'dynamic' && !hasDynamicMinValue) {
|
|
||||||
state.miscForm.gaugeMin = 0
|
|
||||||
state.miscForm.gaugeMinField.id = state.quotaData[0]?.id ?? ''
|
|
||||||
state.miscForm.gaugeMinField.summary = 'sum'
|
|
||||||
state.minField = getQuotaField(state.miscForm.gaugeMinField.id)
|
|
||||||
changeMisc('gaugeMinField', true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const hasFixValue = state.miscForm[maxValueKey]
|
|
||||||
if (isLiquid.value) {
|
|
||||||
state.miscForm[maxTypeKey] = 'fix'
|
|
||||||
state.miscForm[maxValueKey] = hasFixValue
|
|
||||||
? hasFixValue
|
|
||||||
: cloneDeep(defaultMaxValue[maxValueKey]) ?? 0
|
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = ''
|
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = ''
|
|
||||||
}
|
|
||||||
if (isGauge.value) {
|
|
||||||
// max
|
|
||||||
state.miscForm[maxTypeKey] = 'fix'
|
|
||||||
state.miscForm[maxValueKey] = hasFixValue
|
|
||||||
? hasFixValue
|
|
||||||
: cloneDeep(defaultMaxValue[maxValueKey]) ?? 0
|
|
||||||
state.miscForm[maxValueKey + 'Field']['id'] = ''
|
|
||||||
state.miscForm[maxValueKey + 'Field']['summary'] = ''
|
|
||||||
// min
|
|
||||||
state.miscForm.gaugeMinType = 'fix'
|
|
||||||
state.miscForm.gaugeMin = 0
|
|
||||||
state.miscForm.gaugeMinField.id = ''
|
|
||||||
state.miscForm.gaugeMinField.summary = ''
|
|
||||||
}
|
|
||||||
changeMisc('', false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
// 校验聚合函数
|
||||||
init()
|
const validLiquidMaxFieldAgg = computed(() => {
|
||||||
initField()
|
return isAggField(state.miscForm.liquidMaxField)
|
||||||
useEmitt({ name: 'addAxis', callback: addAxis })
|
|
||||||
useEmitt({
|
|
||||||
name: 'chart-data-change',
|
|
||||||
callback: () => {
|
|
||||||
initStateForm()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
useEmitt({
|
const validMinFieldAgg = computed(() => {
|
||||||
name: 'chart-type-change',
|
return isAggField(state.miscForm.gaugeMinField)
|
||||||
callback: () => {
|
|
||||||
if (isLiquid.value || isGauge.value) {
|
|
||||||
init()
|
|
||||||
initField()
|
|
||||||
initAxis(props.chart.yAxis[0]?.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
const validMaxFieldAgg = computed(() => {
|
||||||
|
return isAggField(state.miscForm.gaugeMaxField)
|
||||||
})
|
})
|
||||||
|
const isAggField = field => {
|
||||||
|
return quotaData.value.find(ele => ele.id === field.id)?.agg
|
||||||
|
}
|
||||||
|
// 校验计算字段和聚合函数
|
||||||
|
const validLiquidMaxFieldCalcAndAgg = computed(() => {
|
||||||
|
return isCalcFieldAndAgg(state.miscForm.liquidMaxField)
|
||||||
|
})
|
||||||
|
const validMinFieldCalcAndAgg = computed(() => {
|
||||||
|
return isCalcFieldAndAgg(state.miscForm.gaugeMinField)
|
||||||
|
})
|
||||||
|
const validMaxFieldCalcAndAgg = computed(() => {
|
||||||
|
return isCalcFieldAndAgg(state.miscForm.gaugeMaxField)
|
||||||
|
})
|
||||||
|
const isCalcFieldAndAgg = field => {
|
||||||
|
return quotaData.value.find(ele => ele.id === field.id && ele.extField === 2 && ele.agg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验数值类型
|
||||||
|
const validLiquidMaxFieldNum = computed(() => {
|
||||||
|
return isNumType(state.miscForm.liquidMaxField)
|
||||||
|
})
|
||||||
|
const validMinFieldNum = computed(() => {
|
||||||
|
return isNumType(state.miscForm.gaugeMinField)
|
||||||
|
})
|
||||||
|
const validMaxFieldNum = computed(() => {
|
||||||
|
return isNumType(state.miscForm.gaugeMaxField)
|
||||||
|
})
|
||||||
|
|
||||||
|
const isNumType = field => {
|
||||||
|
return quotaData.value.find(ele => ele.id === field.id && NUMBER_DE_TYPE.includes(ele.deType))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 不包含记录数字段以及计算字段
|
* 计算属性
|
||||||
*/
|
*/
|
||||||
const quotaData = computed(() => {
|
const quotaData = computed(() => {
|
||||||
return state.quotaData.filter(item => NUMBER_DE_TYPE.includes(item.deType))
|
return state.quotaData
|
||||||
})
|
})
|
||||||
const isLiquid = computed(() => props.chart.type === 'liquid')
|
const isLiquid = computed(() => props.chart.type === 'liquid')
|
||||||
const isGauge = computed(() => props.chart.type === 'gauge')
|
const isGauge = computed(() => props.chart.type === 'gauge')
|
||||||
|
onMounted(() => {
|
||||||
|
init()
|
||||||
|
initField()
|
||||||
|
if (
|
||||||
|
(isGauge.value && !state.miscForm.gaugeMaxField.id && !state.miscForm.gaugeMax) ||
|
||||||
|
(isLiquid.value && !state.miscForm.liquidMaxField.id && !state.miscForm.liquidMax)
|
||||||
|
) {
|
||||||
|
initAxis(props.chart.yAxis[0]?.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form :model="state.miscForm">
|
<el-form size="small" :model="state.miscForm">
|
||||||
<el-row :gutter="8">
|
<el-row :gutter="8">
|
||||||
<el-col :span="12" v-show="showProperty('gaugeStartAngle')">
|
<el-col :span="12" v-show="showProperty('gaugeStartAngle')">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
@ -474,14 +372,14 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
v-model="state.miscForm.gaugeMin"
|
v-model="state.miscForm.gaugeMin"
|
||||||
size="small"
|
size="small"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
@change="changeMisc('gaugeMin')"
|
@blur="changeFixedValidate('gaugeMin')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-row
|
<el-row
|
||||||
:gutter="8"
|
:gutter="8"
|
||||||
v-if="showProperty('gaugeMinField') && state.miscForm.gaugeMinType === 'dynamic'"
|
v-if="showProperty('gaugeMinField') && state.miscForm.gaugeMinType === 'dynamic'"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-col :span="validMinFieldCalcAndAgg ? 24 : 12">
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-select
|
<el-select
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -511,7 +409,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12" v-if="!validMinFieldCalcAndAgg">
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-select
|
<el-select
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -519,6 +417,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
v-model="state.miscForm.gaugeMinField.summary"
|
v-model="state.miscForm.gaugeMinField.summary"
|
||||||
@change="changeQuotaField('min')"
|
@change="changeQuotaField('min')"
|
||||||
>
|
>
|
||||||
|
<div v-if="!validMinFieldAgg && validMinFieldNum">
|
||||||
<el-option v-if="validMinField" key="sum" value="sum" :label="t('chart.sum')" />
|
<el-option v-if="validMinField" key="sum" value="sum" :label="t('chart.sum')" />
|
||||||
<el-option v-if="validMinField" key="avg" value="avg" :label="t('chart.avg')" />
|
<el-option v-if="validMinField" key="avg" value="avg" :label="t('chart.avg')" />
|
||||||
<el-option v-if="validMinField" key="max" value="max" :label="t('chart.max')" />
|
<el-option v-if="validMinField" key="max" value="max" :label="t('chart.max')" />
|
||||||
@ -535,9 +434,10 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
value="var_pop"
|
value="var_pop"
|
||||||
:label="t('chart.var_pop')"
|
:label="t('chart.var_pop')"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<el-option key="count" value="count" :label="t('chart.count')" />
|
<el-option key="count" value="count" :label="t('chart.count')" />
|
||||||
<el-option
|
<el-option
|
||||||
v-if="state.minField.id !== '-1'"
|
v-if="state.miscForm.gaugeMinField.id !== '-1'"
|
||||||
key="count_distinct"
|
key="count_distinct"
|
||||||
value="count_distinct"
|
value="count_distinct"
|
||||||
:label="t('chart.count_distinct')"
|
:label="t('chart.count_distinct')"
|
||||||
@ -573,14 +473,15 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
v-model="state.miscForm.gaugeMax"
|
v-model="state.miscForm.gaugeMax"
|
||||||
size="small"
|
size="small"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
@change="changeMaxValidate('gaugeMax')"
|
value-on-clear="gaugeLiquidYaxisDefaultValue.gaugeMax"
|
||||||
|
@blur="changeFixedValidate('gaugeMax')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-row
|
<el-row
|
||||||
:gutter="8"
|
:gutter="8"
|
||||||
v-if="showProperty('gaugeMaxField') && state.miscForm.gaugeMaxType === 'dynamic'"
|
v-if="showProperty('gaugeMaxField') && state.miscForm.gaugeMaxType === 'dynamic'"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-col :span="validMaxFieldCalcAndAgg ? 24 : 12">
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-select
|
<el-select
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -610,7 +511,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12" v-if="!validMaxFieldCalcAndAgg">
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-select
|
<el-select
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -618,6 +519,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
:placeholder="t('chart.summary')"
|
:placeholder="t('chart.summary')"
|
||||||
@change="changeQuotaField('max')"
|
@change="changeQuotaField('max')"
|
||||||
>
|
>
|
||||||
|
<div v-if="!validMaxFieldAgg && validMaxFieldNum">
|
||||||
<el-option v-if="validMaxField" key="sum" value="sum" :label="t('chart.sum')" />
|
<el-option v-if="validMaxField" key="sum" value="sum" :label="t('chart.sum')" />
|
||||||
<el-option v-if="validMaxField" key="avg" value="avg" :label="t('chart.avg')" />
|
<el-option v-if="validMaxField" key="avg" value="avg" :label="t('chart.avg')" />
|
||||||
<el-option v-if="validMaxField" key="max" value="max" :label="t('chart.max')" />
|
<el-option v-if="validMaxField" key="max" value="max" :label="t('chart.max')" />
|
||||||
@ -634,9 +536,10 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
value="var_pop"
|
value="var_pop"
|
||||||
:label="t('chart.var_pop')"
|
:label="t('chart.var_pop')"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<el-option key="count" value="count" :label="t('chart.count')" />
|
<el-option key="count" value="count" :label="t('chart.count')" />
|
||||||
<el-option
|
<el-option
|
||||||
v-if="state.maxField.id !== '-1'"
|
v-if="state.miscForm.gaugeMaxField.id !== '-1'"
|
||||||
key="count_distinct"
|
key="count_distinct"
|
||||||
value="count_distinct"
|
value="count_distinct"
|
||||||
:label="t('chart.count_distinct')"
|
:label="t('chart.count_distinct')"
|
||||||
@ -723,7 +626,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
v-model="state.miscForm.liquidMax"
|
v-model="state.miscForm.liquidMax"
|
||||||
size="small"
|
size="small"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
@blur="changeMaxValidate('liquidMax')"
|
@blur="changeFixedValidate('liquidMax')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -731,7 +634,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
:gutter="8"
|
:gutter="8"
|
||||||
v-if="showProperty('liquidMaxField') && state.miscForm.liquidMaxType === 'dynamic'"
|
v-if="showProperty('liquidMaxField') && state.miscForm.liquidMaxType === 'dynamic'"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-col :span="validLiquidMaxFieldCalcAndAgg ? 24 : 12">
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-select
|
<el-select
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -761,7 +664,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12" v-if="!validLiquidMaxFieldCalcAndAgg">
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-select
|
<el-select
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -769,6 +672,7 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
:placeholder="t('chart.summary')"
|
:placeholder="t('chart.summary')"
|
||||||
@change="changeQuotaField('max')"
|
@change="changeQuotaField('max')"
|
||||||
>
|
>
|
||||||
|
<div v-if="!validLiquidMaxFieldAgg && validLiquidMaxFieldNum">
|
||||||
<el-option v-if="validLiquidMaxField" key="sum" value="sum" :label="t('chart.sum')" />
|
<el-option v-if="validLiquidMaxField" key="sum" value="sum" :label="t('chart.sum')" />
|
||||||
<el-option v-if="validLiquidMaxField" key="avg" value="avg" :label="t('chart.avg')" />
|
<el-option v-if="validLiquidMaxField" key="avg" value="avg" :label="t('chart.avg')" />
|
||||||
<el-option v-if="validLiquidMaxField" key="max" value="max" :label="t('chart.max')" />
|
<el-option v-if="validLiquidMaxField" key="max" value="max" :label="t('chart.max')" />
|
||||||
@ -785,9 +689,10 @@ const isGauge = computed(() => props.chart.type === 'gauge')
|
|||||||
value="var_pop"
|
value="var_pop"
|
||||||
:label="t('chart.var_pop')"
|
:label="t('chart.var_pop')"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
<el-option key="count" value="count" :label="t('chart.count')" />
|
<el-option key="count" value="count" :label="t('chart.count')" />
|
||||||
<el-option
|
<el-option
|
||||||
v-if="state.liquidMaxField.id !== '-1'"
|
v-if="state.miscForm.liquidMaxField.id !== '-1'"
|
||||||
key="count_distinct"
|
key="count_distinct"
|
||||||
value="count_distinct"
|
value="count_distinct"
|
||||||
:label="t('chart.count_distinct')"
|
:label="t('chart.count_distinct')"
|
||||||
|
@ -16,7 +16,7 @@ const props = withDefaults(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
|
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
@ -83,7 +83,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="miscForm" :model="state.miscForm">
|
<el-form size="small" ref="miscForm" :model="state.miscForm">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="showProperty('showName')"
|
v-if="showProperty('showName')"
|
||||||
class="form-item form-item-checkbox"
|
class="form-item form-item-checkbox"
|
||||||
|
@ -50,7 +50,7 @@ const state = reactive({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['onChangeQuadrantForm'])
|
const emit = defineEmits(['onChangeQuadrantForm'])
|
||||||
|
|
||||||
|
@ -0,0 +1,194 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
||||||
|
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
|
import { cloneDeep, defaultsDeep, filter, find } from 'lodash-es'
|
||||||
|
|
||||||
|
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 state = reactive({
|
||||||
|
basicStyleForm: JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE)) as ChartBasicStyle,
|
||||||
|
currentAxis: undefined as string,
|
||||||
|
currentAxisSummary: undefined as {
|
||||||
|
show: boolean
|
||||||
|
field: string
|
||||||
|
summary: string
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['onBasicStyleChange'])
|
||||||
|
const changeBasicStyle = (prop?: string, requestData = false) => {
|
||||||
|
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData }, prop)
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[
|
||||||
|
() => props.chart.customAttr.basicStyle.showSummary,
|
||||||
|
() => props.chart.xAxis,
|
||||||
|
() => props.chart.yAxis
|
||||||
|
],
|
||||||
|
() => {
|
||||||
|
init()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function getAxisList() {
|
||||||
|
return props.chart.type === 'table-info'
|
||||||
|
? filter(props.chart.xAxis, axis => [2, 3, 4].includes(axis.deType))
|
||||||
|
: props.chart.yAxis
|
||||||
|
}
|
||||||
|
|
||||||
|
const computedAxis = computed(() => {
|
||||||
|
return getAxisList()
|
||||||
|
})
|
||||||
|
const summaryTypes = [
|
||||||
|
{ key: 'sum', name: t('chart.sum') },
|
||||||
|
{ key: 'avg', name: t('chart.avg') },
|
||||||
|
{ key: 'max', name: t('chart.max') },
|
||||||
|
{ key: 'min', name: t('chart.min') }
|
||||||
|
// { key: 'stddev_pop', name: t('chart.stddev_pop') },
|
||||||
|
// { key: 'var_pop', name: t('chart.var_pop') }
|
||||||
|
]
|
||||||
|
|
||||||
|
function onSelectAxis(value) {
|
||||||
|
state.currentAxisSummary = find(state.basicStyleForm.seriesSummary, s => s.field === value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const basicStyle = cloneDeep(props.chart.customAttr.basicStyle)
|
||||||
|
|
||||||
|
state.basicStyleForm = defaultsDeep(basicStyle, cloneDeep(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
||||||
|
|
||||||
|
const axisList = getAxisList()
|
||||||
|
|
||||||
|
const tempList = []
|
||||||
|
for (let i = 0; i < axisList.length; i++) {
|
||||||
|
const axis = axisList[i]
|
||||||
|
let savedAxis = find(state.basicStyleForm.seriesSummary, s => s.field === axis.dataeaseName)
|
||||||
|
if (savedAxis) {
|
||||||
|
if (savedAxis.summary == undefined) {
|
||||||
|
savedAxis.summary = 'sum'
|
||||||
|
}
|
||||||
|
if (savedAxis.show == undefined) {
|
||||||
|
savedAxis.show = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
savedAxis = {
|
||||||
|
field: axis.dataeaseName,
|
||||||
|
summary: 'sum',
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tempList.push(savedAxis)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.basicStyleForm.seriesSummary = tempList
|
||||||
|
|
||||||
|
if (state.basicStyleForm.seriesSummary.length > 0 && state.basicStyleForm.showSummary) {
|
||||||
|
state.currentAxis = state.basicStyleForm.seriesSummary[0].field
|
||||||
|
onSelectAxis(state.currentAxis)
|
||||||
|
} else {
|
||||||
|
state.currentAxis = undefined
|
||||||
|
state.currentAxisSummary = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div style="width: 100%">
|
||||||
|
<el-form
|
||||||
|
ref="summaryForm"
|
||||||
|
:disabled="!state.basicStyleForm.showSummary"
|
||||||
|
:model="state.basicStyleForm"
|
||||||
|
size="small"
|
||||||
|
label-position="top"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
v-if="showProperty('summaryLabel')"
|
||||||
|
:label="t('chart.table_summary_label')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
class="form-item"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
v-model="state.basicStyleForm.summaryLabel"
|
||||||
|
type="text"
|
||||||
|
:effect="themes"
|
||||||
|
:max-length="10"
|
||||||
|
@blur="changeBasicStyle('summaryLabel')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
|
<el-select
|
||||||
|
v-model="state.currentAxis"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
class="form-item"
|
||||||
|
@change="onSelectAxis"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="c in computedAxis"
|
||||||
|
:key="c.dataeaseName"
|
||||||
|
:value="c.dataeaseName"
|
||||||
|
:label="c.chartShowName ?? c.name"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<template v-if="state.currentAxis && state.currentAxisSummary">
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
|
<el-checkbox
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.currentAxisSummary.show"
|
||||||
|
@change="changeBasicStyle('seriesSummary')"
|
||||||
|
>
|
||||||
|
{{ t('chart.table_show_summary') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="indented-container">
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
|
<el-select
|
||||||
|
v-model="state.currentAxisSummary.summary"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
class="form-item"
|
||||||
|
:disabled="!state.currentAxisSummary.show"
|
||||||
|
@change="changeBasicStyle('seriesSummary')"
|
||||||
|
>
|
||||||
|
<el-option v-for="c in summaryTypes" :key="c.key" :value="c.key" :label="c.name" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.indented-container {
|
||||||
|
margin-top: 8px;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 22px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -154,7 +154,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div style="width: 100%">
|
<el-form size="small" style="width: 100%">
|
||||||
<div class="map-flow-style" v-if="showProperty('symbolicMapStyle')">
|
<div class="map-flow-style" v-if="showProperty('symbolicMapStyle')">
|
||||||
<el-row style="flex: 1">
|
<el-row style="flex: 1">
|
||||||
<el-col>
|
<el-col>
|
||||||
@ -303,7 +303,7 @@ onMounted(() => {
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
@ -41,7 +41,7 @@ const props = defineProps({
|
|||||||
const appearanceStore = useAppearanceStoreWithOut()
|
const appearanceStore = useAppearanceStoreWithOut()
|
||||||
const emit = defineEmits(['onTextChange'])
|
const emit = defineEmits(['onTextChange'])
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const fontFamily = CHART_FONT_FAMILY.concat(
|
const fontFamily = CHART_FONT_FAMILY.concat(
|
||||||
@ -132,6 +132,7 @@ watch(
|
|||||||
:disabled="!state.titleForm.show"
|
:disabled="!state.titleForm.show"
|
||||||
:model="state.titleForm"
|
:model="state.titleForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.title')"
|
:label="t('chart.title')"
|
||||||
@ -202,7 +203,11 @@ watch(
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
|
<el-form-item
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="width: 106px; padding-left: 4px"
|
||||||
|
>
|
||||||
<el-select
|
<el-select
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.titleForm.letterSpace"
|
v-model="state.titleForm.letterSpace"
|
||||||
@ -210,7 +215,7 @@ watch(
|
|||||||
@change="changeTitleStyle('letterSpace')"
|
@change="changeTitleStyle('letterSpace')"
|
||||||
>
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<el-icon>
|
<el-icon size="16">
|
||||||
<Icon name="icon_letter-spacing_outlined"
|
<Icon name="icon_letter-spacing_outlined"
|
||||||
><icon_letterSpacing_outlined class="svg-icon"
|
><icon_letterSpacing_outlined class="svg-icon"
|
||||||
/></Icon>
|
/></Icon>
|
||||||
|
@ -3,10 +3,16 @@ import icon_info_outlined from '@/assets/svg/icon_info_outlined.svg'
|
|||||||
import { PropType, computed, onMounted, reactive, watch, ref, inject } from 'vue'
|
import { PropType, computed, onMounted, reactive, watch, ref, inject } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_TOOLTIP } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_PANEL, DEFAULT_TOOLTIP } from '@/views/chart/components/editor/util/chart'
|
||||||
import { ElIcon, ElSpace } from 'element-plus-secondary'
|
import { ElFormItem, ElIcon, ElSpace } from 'element-plus-secondary'
|
||||||
import cloneDeep from 'lodash-es/cloneDeep'
|
import cloneDeep from 'lodash-es/cloneDeep'
|
||||||
import defaultsDeep from 'lodash-es/defaultsDeep'
|
import defaultsDeep from 'lodash-es/defaultsDeep'
|
||||||
import { formatterType, unitType } from '../../../js/formatter'
|
import {
|
||||||
|
isEnLocal,
|
||||||
|
formatterType,
|
||||||
|
getUnitTypeList,
|
||||||
|
initFormatCfgUnit,
|
||||||
|
onChangeFormatCfgUnitLanguage
|
||||||
|
} from '@/views/chart/components/js/formatter'
|
||||||
import { fieldType } from '@/utils/attr'
|
import { fieldType } from '@/utils/attr'
|
||||||
import { defaultTo, partition, map, includes, isEmpty } from 'lodash-es'
|
import { defaultTo, partition, map, includes, isEmpty } from 'lodash-es'
|
||||||
import chartViewManager from '../../../js/panel'
|
import chartViewManager from '../../../js/panel'
|
||||||
@ -39,7 +45,7 @@ const dvMainStore = dvMainStoreWithOut()
|
|||||||
const { batchOptStatus, mobileInPc } = storeToRefs(dvMainStore)
|
const { batchOptStatus, mobileInPc } = storeToRefs(dvMainStore)
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['onTooltipChange', 'onExtTooltipChange'])
|
const emit = defineEmits(['onTooltipChange', 'onExtTooltipChange'])
|
||||||
const curSeriesFormatter = ref<DeepPartial<SeriesFormatter>>({})
|
const curSeriesFormatter = ref<DeepPartial<SeriesFormatter>>({})
|
||||||
@ -63,6 +69,7 @@ const changeChartType = () => {
|
|||||||
formatter.splice(0, formatter.length)
|
formatter.splice(0, formatter.length)
|
||||||
const axisIds = []
|
const axisIds = []
|
||||||
quotaAxis.value.forEach(axis => {
|
quotaAxis.value.forEach(axis => {
|
||||||
|
initFormatCfgUnit(axis.formatterCfg)
|
||||||
formatter.push({
|
formatter.push({
|
||||||
...axis,
|
...axis,
|
||||||
show: true
|
show: true
|
||||||
@ -71,6 +78,7 @@ const changeChartType = () => {
|
|||||||
})
|
})
|
||||||
quotaData.value.forEach(quotaAxis => {
|
quotaData.value.forEach(quotaAxis => {
|
||||||
if (!axisIds.includes(quotaAxis.id)) {
|
if (!axisIds.includes(quotaAxis.id)) {
|
||||||
|
initFormatCfgUnit(quotaAxis.formatterCfg)
|
||||||
formatter.push({
|
formatter.push({
|
||||||
...quotaAxis,
|
...quotaAxis,
|
||||||
seriesId: quotaAxis.id,
|
seriesId: quotaAxis.id,
|
||||||
@ -78,6 +86,9 @@ const changeChartType = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (formatter[0]) {
|
||||||
|
curSeriesFormatter.value = formatter[0]
|
||||||
|
}
|
||||||
emit('onTooltipChange', { data: state.tooltipForm, render: false }, 'seriesTooltipFormatter')
|
emit('onTooltipChange', { data: state.tooltipForm, render: false }, 'seriesTooltipFormatter')
|
||||||
emit('onExtTooltipChange', extTooltip.value)
|
emit('onExtTooltipChange', extTooltip.value)
|
||||||
}
|
}
|
||||||
@ -101,6 +112,9 @@ const changeDataset = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (formatter[0]) {
|
||||||
|
curSeriesFormatter.value = formatter[0]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AXIS_PROP: AxisType[] = ['yAxis', 'yAxisExt', 'extBubble']
|
const AXIS_PROP: AxisType[] = ['yAxis', 'yAxisExt', 'extBubble']
|
||||||
@ -229,6 +243,12 @@ const changeTooltipAttr = (prop: string, requestData = false, render = true) =>
|
|||||||
}
|
}
|
||||||
emit('onTooltipChange', { data: state.tooltipForm, requestData, render }, prop)
|
emit('onTooltipChange', { data: state.tooltipForm, requestData, render }, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeUnitLanguage(cfg: BaseFormatter, lang, prop: string) {
|
||||||
|
onChangeFormatCfgUnitLanguage(cfg, lang)
|
||||||
|
changeTooltipAttr(prop)
|
||||||
|
}
|
||||||
|
|
||||||
const formatterSelector = ref()
|
const formatterSelector = ref()
|
||||||
const init = () => {
|
const init = () => {
|
||||||
const chart = JSON.parse(JSON.stringify(props.chart))
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
@ -236,6 +256,9 @@ const init = () => {
|
|||||||
const customAttr = JSON.parse(JSON.stringify(chart.customAttr))
|
const customAttr = JSON.parse(JSON.stringify(chart.customAttr))
|
||||||
if (customAttr.tooltip) {
|
if (customAttr.tooltip) {
|
||||||
state.tooltipForm = defaultsDeep(customAttr.tooltip, cloneDeep(DEFAULT_TOOLTIP))
|
state.tooltipForm = defaultsDeep(customAttr.tooltip, cloneDeep(DEFAULT_TOOLTIP))
|
||||||
|
|
||||||
|
initFormatCfgUnit(state.tooltipForm.tooltipFormatter)
|
||||||
|
|
||||||
formatterSelector.value?.blur()
|
formatterSelector.value?.blur()
|
||||||
// 新增图表
|
// 新增图表
|
||||||
const formatter = state.tooltipForm.seriesTooltipFormatter
|
const formatter = state.tooltipForm.seriesTooltipFormatter
|
||||||
@ -244,6 +267,9 @@ const init = () => {
|
|||||||
curSeriesFormatter.value = {}
|
curSeriesFormatter.value = {}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
formatter.forEach(f => {
|
||||||
|
initFormatCfgUnit(f.formatterCfg)
|
||||||
|
})
|
||||||
const seriesAxisMap = formatter.reduce((pre, next) => {
|
const seriesAxisMap = formatter.reduce((pre, next) => {
|
||||||
next.seriesId = next.seriesId ?? next.id
|
next.seriesId = next.seriesId ?? next.id
|
||||||
pre[next.seriesId] = next
|
pre[next.seriesId] = next
|
||||||
@ -251,6 +277,9 @@ const init = () => {
|
|||||||
}, {})
|
}, {})
|
||||||
if (!curSeriesFormatter?.value || !seriesAxisMap[curSeriesFormatter.value?.seriesId]) {
|
if (!curSeriesFormatter?.value || !seriesAxisMap[curSeriesFormatter.value?.seriesId]) {
|
||||||
curSeriesFormatter.value = {}
|
curSeriesFormatter.value = {}
|
||||||
|
if (formatter[0]) {
|
||||||
|
curSeriesFormatter.value = formatter[0]
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
curSeriesFormatter.value = seriesAxisMap[curSeriesFormatter.value?.seriesId]
|
curSeriesFormatter.value = seriesAxisMap[curSeriesFormatter.value?.seriesId]
|
||||||
}
|
}
|
||||||
@ -443,6 +472,7 @@ onMounted(() => {
|
|||||||
:disabled="!state.tooltipForm.show"
|
:disabled="!state.tooltipForm.show"
|
||||||
:model="state.tooltipForm"
|
:model="state.tooltipForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.background') + t('chart.color')"
|
:label="t('chart.background') + t('chart.color')"
|
||||||
@ -590,8 +620,30 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row :gutter="8" v-if="state.tooltipForm.tooltipFormatter.type !== 'percent'">
|
<template v-if="state.tooltipForm.tooltipFormatter.type !== 'percent'">
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
:disabled="state.tooltipForm.tooltipFormatter.type === 'percent'"
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.tooltipForm.tooltipFormatter.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v => changeUnitLanguage(state.tooltipForm.tooltipFormatter, v, 'tooltipFormatter')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_unit')"
|
:label="t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -603,18 +655,20 @@ onMounted(() => {
|
|||||||
v-model="state.tooltipForm.tooltipFormatter.unit"
|
v-model="state.tooltipForm.tooltipFormatter.unit"
|
||||||
:placeholder="t('chart.pls_select_field')"
|
:placeholder="t('chart.pls_select_field')"
|
||||||
size="small"
|
size="small"
|
||||||
@change="changeTooltipAttr('tooltipFormatter.unit')"
|
@change="changeTooltipAttr('tooltipFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(state.tooltipForm.tooltipFormatter.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_suffix')"
|
:label="t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -631,6 +685,7 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -781,8 +836,37 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row :gutter="8" v-if="curSeriesFormatter.formatterCfg.type !== 'percent'">
|
<template v-if="curSeriesFormatter.formatterCfg.type !== 'percent'">
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
:disabled="
|
||||||
|
!curSeriesFormatter.show || curSeriesFormatter.formatterCfg.type == 'percent'
|
||||||
|
"
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="curSeriesFormatter.formatterCfg.unitLanguage"
|
||||||
|
:placeholder="$t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeUnitLanguage(
|
||||||
|
curSeriesFormatter.formatterCfg,
|
||||||
|
v,
|
||||||
|
'seriesTooltipFormatter'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="$t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_unit')"
|
:label="t('chart.value_formatter_unit')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -799,15 +883,17 @@ onMounted(() => {
|
|||||||
@change="changeTooltipAttr('seriesTooltipFormatter')"
|
@change="changeTooltipAttr('seriesTooltipFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitType"
|
v-for="item in getUnitTypeList(curSeriesFormatter.formatterCfg.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.value_formatter_suffix')"
|
:label="t('chart.value_formatter_suffix')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -825,6 +911,7 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@ -872,7 +959,8 @@ onMounted(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
size="middle"
|
size="middle"
|
||||||
:min="0"
|
precision="0"
|
||||||
|
:min="1"
|
||||||
:max="600"
|
:max="600"
|
||||||
:disabled="!state.tooltipForm.carousel.enable"
|
:disabled="!state.tooltipForm.carousel.enable"
|
||||||
@change="changeTooltipAttr('carousel')"
|
@change="changeTooltipAttr('carousel')"
|
||||||
@ -891,7 +979,8 @@ onMounted(() => {
|
|||||||
:effect="themes"
|
:effect="themes"
|
||||||
controls-position="right"
|
controls-position="right"
|
||||||
size="middle"
|
size="middle"
|
||||||
:min="0"
|
precision="0"
|
||||||
|
:min="1"
|
||||||
:max="600"
|
:max="600"
|
||||||
:disabled="!state.tooltipForm.carousel.enable"
|
:disabled="!state.tooltipForm.carousel.enable"
|
||||||
@change="changeTooltipAttr('carousel')"
|
@change="changeTooltipAttr('carousel')"
|
||||||
@ -906,13 +995,8 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.series-select {
|
.series-select {
|
||||||
:deep(.ed-select__prefix--light) {
|
:deep(.ed-select__prefix::after) {
|
||||||
padding-right: unset;
|
display: none;
|
||||||
border-right: unset;
|
|
||||||
}
|
|
||||||
:deep(.ed-select__prefix--dark) {
|
|
||||||
padding-right: unset;
|
|
||||||
border-right: unset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,14 @@ import icon_info_outlined from '@/assets/svg/icon_info_outlined.svg'
|
|||||||
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_XAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_PANEL, DEFAULT_XAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
import { formatterType, unitType } from '@/views/chart/components/js/formatter'
|
import {
|
||||||
import { ElMessage } from 'element-plus-secondary'
|
isEnLocal,
|
||||||
|
formatterType,
|
||||||
|
getUnitTypeList,
|
||||||
|
initFormatCfgUnit,
|
||||||
|
onChangeFormatCfgUnitLanguage
|
||||||
|
} from '@/views/chart/components/js/formatter'
|
||||||
|
import { ElFormItem, ElMessage } from 'element-plus-secondary'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -24,13 +30,12 @@ const props = defineProps({
|
|||||||
|
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const typeList = formatterType
|
const typeList = formatterType
|
||||||
const unitList = unitType
|
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
axisForm: JSON.parse(JSON.stringify(DEFAULT_XAXIS_STYLE))
|
axisForm: JSON.parse(JSON.stringify(DEFAULT_XAXIS_STYLE))
|
||||||
})
|
})
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['onChangeXAxisForm'])
|
const emit = defineEmits(['onChangeXAxisForm'])
|
||||||
|
|
||||||
@ -90,6 +95,11 @@ const changeAxisStyle = prop => {
|
|||||||
emit('onChangeXAxisForm', state.axisForm, prop)
|
emit('onChangeXAxisForm', state.axisForm, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeUnitLanguage(cfg: BaseFormatter, lang, prop: string) {
|
||||||
|
onChangeFormatCfgUnitLanguage(cfg, lang)
|
||||||
|
changeAxisStyle(prop)
|
||||||
|
}
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
const chart = JSON.parse(JSON.stringify(props.chart))
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
if (chart.customStyle) {
|
if (chart.customStyle) {
|
||||||
@ -101,6 +111,7 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
if (customStyle.xAxis) {
|
if (customStyle.xAxis) {
|
||||||
state.axisForm = customStyle.xAxis
|
state.axisForm = customStyle.xAxis
|
||||||
|
initFormatCfgUnit(state.axisForm.axisLabelFormatter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,6 +122,10 @@ const isBidirectionalBar = computed(() => {
|
|||||||
return props.chart.type === 'bidirectional-bar'
|
return props.chart.type === 'bidirectional-bar'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const isBulletGraph = computed(() => {
|
||||||
|
return ['bullet-graph'].includes(props.chart.type)
|
||||||
|
})
|
||||||
|
|
||||||
const isHorizontalLayout = computed(() => {
|
const isHorizontalLayout = computed(() => {
|
||||||
return props.chart.customAttr.basicStyle.layout === 'horizontal'
|
return props.chart.customAttr.basicStyle.layout === 'horizontal'
|
||||||
})
|
})
|
||||||
@ -147,6 +162,20 @@ onMounted(() => {
|
|||||||
t('chart.text_pos_center')
|
t('chart.text_pos_center')
|
||||||
}}</el-radio>
|
}}</el-radio>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="isBulletGraph">
|
||||||
|
<div v-if="isHorizontalLayout">
|
||||||
|
<el-radio :effect="props.themes" label="bottom">{{
|
||||||
|
t('chart.text_pos_left')
|
||||||
|
}}</el-radio>
|
||||||
|
<el-radio :effect="props.themes" label="top">{{ t('chart.text_pos_right') }}</el-radio>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<el-radio :effect="props.themes" label="top">{{ t('chart.text_pos_top') }}</el-radio>
|
||||||
|
<el-radio :effect="props.themes" label="bottom">{{
|
||||||
|
t('chart.text_pos_bottom')
|
||||||
|
}}</el-radio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<el-radio :effect="props.themes" label="top">{{ t('chart.text_pos_top') }}</el-radio>
|
<el-radio :effect="props.themes" label="top">{{ t('chart.text_pos_top') }}</el-radio>
|
||||||
<el-radio :effect="props.themes" label="bottom">{{
|
<el-radio :effect="props.themes" label="bottom">{{
|
||||||
@ -552,13 +581,34 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="
|
v-if="
|
||||||
state.axisForm.axisLabel.show && state.axisForm.axisLabelFormatter.type !== 'percent'
|
state.axisForm.axisLabel.show && state.axisForm.axisLabelFormatter.type !== 'percent'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.axisForm.axisLabelFormatter.unitLanguage"
|
||||||
|
:placeholder="t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeUnitLanguage(state.axisForm.axisLabelFormatter, v, 'axisLabelFormatter')
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
@ -569,18 +619,20 @@ onMounted(() => {
|
|||||||
v-model="state.axisForm.axisLabelFormatter.unit"
|
v-model="state.axisForm.axisLabelFormatter.unit"
|
||||||
:placeholder="t('chart.pls_select_field')"
|
:placeholder="t('chart.pls_select_field')"
|
||||||
size="small"
|
size="small"
|
||||||
@change="changeAxisStyle('axisLabelFormatter.unit')"
|
@change="changeAxisStyle('axisLabelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitList"
|
v-for="item in getUnitTypeList(state.axisForm.axisLabelFormatter.unitLanguage)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
@ -598,6 +650,7 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
|
@ -3,8 +3,14 @@ import icon_info_outlined from '@/assets/svg/icon_info_outlined.svg'
|
|||||||
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_YAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_PANEL, DEFAULT_YAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
import { formatterType, unitType } from '@/views/chart/components/js/formatter'
|
import {
|
||||||
import { ElMessage } from 'element-plus-secondary'
|
isEnLocal,
|
||||||
|
formatterType,
|
||||||
|
getUnitTypeList,
|
||||||
|
initFormatCfgUnit,
|
||||||
|
onChangeFormatCfgUnitLanguage
|
||||||
|
} from '@/views/chart/components/js/formatter'
|
||||||
|
import { ElFormItem, ElMessage } from 'element-plus-secondary'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -24,9 +30,8 @@ const props = defineProps({
|
|||||||
|
|
||||||
const predefineColors = COLOR_PANEL
|
const predefineColors = COLOR_PANEL
|
||||||
const typeList = formatterType
|
const typeList = formatterType
|
||||||
const unitList = unitType
|
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes === 'dark' ? 'light' : 'dark'
|
||||||
})
|
})
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
axisForm: JSON.parse(JSON.stringify(DEFAULT_YAXIS_STYLE))
|
axisForm: JSON.parse(JSON.stringify(DEFAULT_YAXIS_STYLE))
|
||||||
@ -76,6 +81,11 @@ const changeAxisStyle = prop => {
|
|||||||
emit('onChangeYAxisForm', state.axisForm, prop)
|
emit('onChangeYAxisForm', state.axisForm, prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeUnitLanguage(cfg: BaseFormatter, lang, prop: string) {
|
||||||
|
onChangeFormatCfgUnitLanguage(cfg, lang)
|
||||||
|
changeAxisStyle(prop)
|
||||||
|
}
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
const chart = JSON.parse(JSON.stringify(props.chart))
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
if (chart.customStyle) {
|
if (chart.customStyle) {
|
||||||
@ -87,11 +97,19 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
if (customStyle.yAxis) {
|
if (customStyle.yAxis) {
|
||||||
state.axisForm = customStyle.yAxis
|
state.axisForm = customStyle.yAxis
|
||||||
|
initFormatCfgUnit(state.axisForm.axisLabelFormatter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
const showProperty = prop => props.propertyInner?.includes(prop)
|
||||||
|
const isBulletGraph = computed(() => {
|
||||||
|
return ['bullet-graph'].includes(props.chart.type)
|
||||||
|
})
|
||||||
|
|
||||||
|
const isHorizontalLayout = computed(() => {
|
||||||
|
return props.chart.customAttr.basicStyle.layout === 'horizontal'
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init()
|
init()
|
||||||
@ -117,8 +135,24 @@ onMounted(() => {
|
|||||||
size="small"
|
size="small"
|
||||||
@change="changeAxisStyle('position')"
|
@change="changeAxisStyle('position')"
|
||||||
>
|
>
|
||||||
|
<div v-if="isBulletGraph">
|
||||||
|
<div v-if="isHorizontalLayout">
|
||||||
|
<el-radio :effect="props.themes" label="right">{{ t('chart.text_pos_top') }}</el-radio>
|
||||||
|
<el-radio :effect="props.themes" label="left">{{
|
||||||
|
t('chart.text_pos_bottom')
|
||||||
|
}}</el-radio>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<el-radio :effect="props.themes" label="left">{{ t('chart.text_pos_left') }}</el-radio>
|
||||||
|
<el-radio :effect="props.themes" label="right">{{
|
||||||
|
t('chart.text_pos_right')
|
||||||
|
}}</el-radio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
<el-radio :effect="props.themes" label="left">{{ t('chart.text_pos_left') }}</el-radio>
|
<el-radio :effect="props.themes" label="left">{{ t('chart.text_pos_left') }}</el-radio>
|
||||||
<el-radio :effect="props.themes" label="right">{{ t('chart.text_pos_right') }}</el-radio>
|
<el-radio :effect="props.themes" label="right">{{ t('chart.text_pos_right') }}</el-radio>
|
||||||
|
</div>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
@ -528,13 +562,38 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-row
|
<template
|
||||||
:gutter="8"
|
|
||||||
v-if="
|
v-if="
|
||||||
state.axisForm.axisLabel.show && state.axisForm.axisLabelFormatter.type !== 'percent'
|
state.axisForm.axisLabel.show && state.axisForm.axisLabelFormatter.type !== 'percent'
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-col :span="12">
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="12" v-if="!isEnLocal">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.value_formatter_unit_language')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-select
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.axisForm.axisLabelFormatter.unitLanguage"
|
||||||
|
:placeholder="t('chart.pls_select_field')"
|
||||||
|
@change="
|
||||||
|
v =>
|
||||||
|
changeUnitLanguage(
|
||||||
|
state.axisForm.axisLabelFormatter,
|
||||||
|
v,
|
||||||
|
'axisLabelFormatter'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_ch')" value="ch" />
|
||||||
|
<el-option :label="t('chart.value_formatter_unit_language_en')" value="en" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="isEnLocal ? 24 : 12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
@ -545,18 +604,22 @@ onMounted(() => {
|
|||||||
v-model="state.axisForm.axisLabelFormatter.unit"
|
v-model="state.axisForm.axisLabelFormatter.unit"
|
||||||
:placeholder="t('chart.pls_select_field')"
|
:placeholder="t('chart.pls_select_field')"
|
||||||
size="small"
|
size="small"
|
||||||
@change="changeAxisStyle('axisLabelFormatter.unit')"
|
@change="changeAxisStyle('axisLabelFormatter')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in unitList"
|
v-for="item in getUnitTypeList(
|
||||||
|
state.axisForm.axisLabelFormatter.unitLanguage
|
||||||
|
)"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
:label="t('chart.' + item.name)"
|
:label="item.name"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
</el-row>
|
||||||
|
<el-row :gutter="8">
|
||||||
|
<el-col :span="24">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
@ -574,6 +637,7 @@ onMounted(() => {
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
<script lang="tsx" setup>
|
||||||
|
import { onMounted, PropType, reactive, watch } from 'vue'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { COLOR_PANEL, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
||||||
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const props = defineProps({
|
||||||
|
chart: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
themes: {
|
||||||
|
type: String as PropType<EditorTheme>,
|
||||||
|
default: 'dark'
|
||||||
|
},
|
||||||
|
propertyInner: {
|
||||||
|
type: Array<string>
|
||||||
|
},
|
||||||
|
selectorType: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const predefineColors = COLOR_PANEL
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
bulletMeasureForm: {
|
||||||
|
bar: {
|
||||||
|
measures: {
|
||||||
|
fill: 'rgba(0,128,255,1)',
|
||||||
|
size: 15,
|
||||||
|
name: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
||||||
|
watch(
|
||||||
|
() => props.chart.customAttr.misc,
|
||||||
|
() => {
|
||||||
|
init()
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
const changeStyle = (prop?) => {
|
||||||
|
emit(
|
||||||
|
'onMiscChange',
|
||||||
|
{ data: { bullet: { ...state.bulletMeasureForm } }, requestData: true },
|
||||||
|
prop
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
|
if (chart.customAttr) {
|
||||||
|
let customAttr = null
|
||||||
|
if (Object.prototype.toString.call(chart.customAttr) === '[object Object]') {
|
||||||
|
customAttr = JSON.parse(JSON.stringify(chart.customAttr))
|
||||||
|
} else {
|
||||||
|
customAttr = JSON.parse(chart.customAttr)
|
||||||
|
}
|
||||||
|
state.bulletMeasureForm = defaultsDeep(customAttr.misc.bullet, cloneDeep(DEFAULT_MISC.bullet))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="bulletMeasureForm"
|
||||||
|
:model="state.bulletMeasureForm"
|
||||||
|
size="small"
|
||||||
|
label-position="top"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<div v-if="selectorType === 'measure'">
|
||||||
|
<div style="flex: 1; display: flex">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('visualization.backgroundColor')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-right: 4px"
|
||||||
|
>
|
||||||
|
<el-color-picker
|
||||||
|
v-model="state.bulletMeasureForm.bar.measures.fill"
|
||||||
|
:predefine="predefineColors"
|
||||||
|
:effect="themes"
|
||||||
|
@change="changeStyle('bar.measures.fill')"
|
||||||
|
show-alpha
|
||||||
|
is-custom
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.radar_size')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-left: 4px; width: 100%"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
:effect="props.themes"
|
||||||
|
v-model="state.bulletMeasureForm.bar.measures.size"
|
||||||
|
:min="1"
|
||||||
|
:max="100"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeStyle('bar.measures.size')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
@ -0,0 +1,259 @@
|
|||||||
|
<script lang="tsx" setup>
|
||||||
|
import { reactive, onMounted, watch } from 'vue'
|
||||||
|
import { COLOR_PANEL, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
||||||
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
const { t } = useI18n()
|
||||||
|
const props = defineProps({
|
||||||
|
chart: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
themes: {
|
||||||
|
type: String,
|
||||||
|
default: 'dark'
|
||||||
|
},
|
||||||
|
propertyInner: {
|
||||||
|
type: Array
|
||||||
|
},
|
||||||
|
selectorType: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const predefineColors = COLOR_PANEL
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
bulletRangeForm: {
|
||||||
|
bar: {
|
||||||
|
ranges: {
|
||||||
|
fill: 'rgba(0,128,255,0.5)',
|
||||||
|
size: 20,
|
||||||
|
showType: 'dynamic',
|
||||||
|
fixedRange: [],
|
||||||
|
fixedRangeNumber: 3,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 10,
|
||||||
|
name: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rangeList: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.chart.customAttr.misc,
|
||||||
|
() => {
|
||||||
|
init()
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const changeStyle = (prop?) => {
|
||||||
|
if (state.bulletRangeForm.bar.ranges.showType === 'fixed' && state.rangeList.length) {
|
||||||
|
state.bulletRangeForm.bar.ranges.fixedRange = cloneDeep(state.rangeList)
|
||||||
|
}
|
||||||
|
emit('onMiscChange', { data: { bullet: { ...state.bulletRangeForm } }, requestData: true }, prop)
|
||||||
|
}
|
||||||
|
const changeRangeNumber = () => {
|
||||||
|
if (state.bulletRangeForm.bar.ranges.fixedRangeNumber === null) {
|
||||||
|
state.bulletRangeForm.bar.ranges.fixedRangeNumber = 1
|
||||||
|
}
|
||||||
|
if (state.rangeList.length > state.bulletRangeForm.bar.ranges.fixedRangeNumber) {
|
||||||
|
state.rangeList = state.rangeList.slice(0, state.bulletRangeForm.bar.ranges.fixedRangeNumber)
|
||||||
|
} else {
|
||||||
|
for (
|
||||||
|
let i = state.rangeList.length;
|
||||||
|
i < state.bulletRangeForm.bar.ranges.fixedRangeNumber;
|
||||||
|
i++
|
||||||
|
) {
|
||||||
|
state.rangeList.push({
|
||||||
|
name: t('chart.symbolic_range') + (i + 1),
|
||||||
|
fixedRangeValue: undefined,
|
||||||
|
fill: 'rgba(0,128,255,0.44)'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changeRangeItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeRangeItem = () => {
|
||||||
|
validateRangeList() && changeStyle()
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateRangeList = () => {
|
||||||
|
return state.rangeList.every(
|
||||||
|
item => item.name && item.fixedRangeValue !== null && item.fixedRangeValue !== undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
|
if (chart.customAttr) {
|
||||||
|
let customAttr = null
|
||||||
|
if (Object.prototype.toString.call(chart.customAttr) === '[object Object]') {
|
||||||
|
customAttr = JSON.parse(JSON.stringify(chart.customAttr))
|
||||||
|
} else {
|
||||||
|
customAttr = JSON.parse(chart.customAttr)
|
||||||
|
}
|
||||||
|
state.bulletRangeForm = defaultsDeep(customAttr.misc.bullet, cloneDeep(DEFAULT_MISC.bullet))
|
||||||
|
getRangeList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRangeList = () => {
|
||||||
|
const range = []
|
||||||
|
if (state.bulletRangeForm.bar.ranges?.fixedRange?.length) {
|
||||||
|
state.rangeList = state.bulletRangeForm.bar.ranges.fixedRange
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < state.bulletRangeForm.bar.ranges.fixedRangeNumber; i++) {
|
||||||
|
range.push({
|
||||||
|
name: '区间' + (i + 1),
|
||||||
|
fixedRangeValue: undefined,
|
||||||
|
fill: 'rgba(0,128,255,0)'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
state.rangeList = cloneDeep(range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeShowType = () => {
|
||||||
|
if (state.bulletRangeForm.bar.ranges.showType === 'dynamic') {
|
||||||
|
changeStyle()
|
||||||
|
} else {
|
||||||
|
changeRangeItem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="bulletRangeForm"
|
||||||
|
:model="state.bulletRangeForm"
|
||||||
|
size="small"
|
||||||
|
label-position="top"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<div v-if="selectorType === 'range'">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.radar_size')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-left: 4px; width: 100%"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
:effect="props.themes"
|
||||||
|
v-model="state.bulletRangeForm.bar.ranges.size"
|
||||||
|
:min="1"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeStyle('bar.ranges.size')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
|
<el-radio-group
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.bulletRangeForm.bar.ranges.showType"
|
||||||
|
@change="changeShowType()"
|
||||||
|
>
|
||||||
|
<el-radio :effect="themes" label="dynamic">{{ t('chart.dynamic') }}</el-radio>
|
||||||
|
<el-radio :effect="themes" label="fixed">{{ t('chart.fix') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<div v-if="state.bulletRangeForm.bar.ranges.showType === 'dynamic'">
|
||||||
|
<div style="flex: 1; display: flex">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('visualization.backgroundColor')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-right: 4px"
|
||||||
|
>
|
||||||
|
<el-color-picker
|
||||||
|
v-model="state.bulletRangeForm.bar.ranges.fill"
|
||||||
|
:predefine="predefineColors"
|
||||||
|
:effect="themes"
|
||||||
|
@change="changeStyle('bar.ranges.fill')"
|
||||||
|
show-alpha
|
||||||
|
is-custom
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="state.bulletRangeForm.bar.ranges.showType === 'fixed'">
|
||||||
|
<div style="flex: 1; display: flex">
|
||||||
|
<el-form-item
|
||||||
|
style="width: 100%"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
:label="t('chart.range_num')"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.bulletRangeForm.bar.ranges.fixedRangeNumber"
|
||||||
|
:precision="0"
|
||||||
|
:min="1"
|
||||||
|
:max="9"
|
||||||
|
:step="1"
|
||||||
|
:controls="true"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeRangeNumber()"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1; display: flex" v-for="(item, index) in state.rangeList" :key="index">
|
||||||
|
<el-form-item
|
||||||
|
:label="index === 0 ? t('chart.threshold_value') : ' '"
|
||||||
|
style="width: 170px"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
:effect="themes"
|
||||||
|
v-model="item.fixedRangeValue"
|
||||||
|
:min="0"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeRangeItem()"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="index === 0 ? t('chart.show_name') : ' '"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-left: 4px"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
:effect="themes"
|
||||||
|
v-model="item.name"
|
||||||
|
size="small"
|
||||||
|
@change="changeRangeItem()"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="index === 0 ? t('visualization.backgroundColor') : ' '"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-left: 4px"
|
||||||
|
>
|
||||||
|
<el-color-picker
|
||||||
|
v-model="item.fill"
|
||||||
|
:predefine="predefineColors"
|
||||||
|
:effect="themes"
|
||||||
|
@change="changeRangeItem()"
|
||||||
|
show-alpha
|
||||||
|
is-custom
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
@ -0,0 +1,183 @@
|
|||||||
|
<script lang="tsx" setup>
|
||||||
|
import { onMounted, PropType, reactive, watch } from 'vue'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { COLOR_PANEL, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
||||||
|
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const props = defineProps({
|
||||||
|
chart: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
themes: {
|
||||||
|
type: String as PropType<EditorTheme>,
|
||||||
|
default: 'dark'
|
||||||
|
},
|
||||||
|
propertyInner: {
|
||||||
|
type: Array<string>
|
||||||
|
},
|
||||||
|
selectorType: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const predefineColors = COLOR_PANEL
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
bulletTargetForm: {
|
||||||
|
bar: {
|
||||||
|
target: {
|
||||||
|
fill: 'rgb(0,0,0)',
|
||||||
|
size: 20,
|
||||||
|
showType: 'dynamic',
|
||||||
|
value: 0,
|
||||||
|
name: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
||||||
|
watch(
|
||||||
|
() => props.chart.customAttr.misc,
|
||||||
|
() => {
|
||||||
|
init()
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
const changeStyle = (prop?) => {
|
||||||
|
if (state.bulletTargetForm.bar.target.value === null) {
|
||||||
|
state.bulletTargetForm.bar.target.value = 1
|
||||||
|
}
|
||||||
|
emit('onMiscChange', { data: { bullet: { ...state.bulletTargetForm } }, requestData: true }, prop)
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const chart = JSON.parse(JSON.stringify(props.chart))
|
||||||
|
if (chart.customAttr) {
|
||||||
|
let customAttr = null
|
||||||
|
if (Object.prototype.toString.call(chart.customAttr) === '[object Object]') {
|
||||||
|
customAttr = JSON.parse(JSON.stringify(chart.customAttr))
|
||||||
|
} else {
|
||||||
|
customAttr = JSON.parse(chart.customAttr)
|
||||||
|
}
|
||||||
|
state.bulletTargetForm = defaultsDeep(customAttr.misc.bullet, cloneDeep(DEFAULT_MISC.bullet))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="bulletTargetForm"
|
||||||
|
:model="state.bulletTargetForm"
|
||||||
|
size="small"
|
||||||
|
label-position="top"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<div v-if="selectorType === 'target'">
|
||||||
|
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||||
|
<el-radio-group
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.bulletTargetForm.bar.target.showType"
|
||||||
|
@change="changeStyle('bar.target.name')"
|
||||||
|
>
|
||||||
|
<el-radio :effect="themes" label="dynamic">{{ t('chart.dynamic') }}</el-radio>
|
||||||
|
<el-radio :effect="themes" label="fixed">{{ t('chart.fix') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<div v-if="state.bulletTargetForm.bar.target.showType === 'dynamic'">
|
||||||
|
<div style="flex: 1; display: flex">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('visualization.color')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-right: 4px"
|
||||||
|
>
|
||||||
|
<el-color-picker
|
||||||
|
v-model="state.bulletTargetForm.bar.target.fill"
|
||||||
|
:predefine="predefineColors"
|
||||||
|
:effect="themes"
|
||||||
|
@change="changeStyle('bar.target.fill')"
|
||||||
|
show-alpha
|
||||||
|
is-custom
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.height')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-left: 4px; width: 100%"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
:effect="props.themes"
|
||||||
|
v-model="state.bulletTargetForm.bar.target.size"
|
||||||
|
:min="1"
|
||||||
|
:max="100"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeStyle('bar.target.size')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="state.bulletTargetForm.bar.target.showType === 'fixed'">
|
||||||
|
<div style="flex: 1; display: flex">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.progress_target')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
:effect="props.themes"
|
||||||
|
v-model="state.bulletTargetForm.bar.target.value"
|
||||||
|
:min="1"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeStyle('bar.target.value')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1; display: flex">
|
||||||
|
<el-form-item
|
||||||
|
:label="t('visualization.color')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-left: 4px"
|
||||||
|
>
|
||||||
|
<el-color-picker
|
||||||
|
v-model="state.bulletTargetForm.bar.target.fill"
|
||||||
|
:predefine="predefineColors"
|
||||||
|
:effect="themes"
|
||||||
|
@change="changeStyle('bar.target.fill')"
|
||||||
|
show-alpha
|
||||||
|
is-custom
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
:label="t('chart.height')"
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
style="padding-left: 4px; width: 100%"
|
||||||
|
>
|
||||||
|
<el-input-number
|
||||||
|
:effect="props.themes"
|
||||||
|
v-model="state.bulletTargetForm.bar.target.size"
|
||||||
|
:min="1"
|
||||||
|
:max="100"
|
||||||
|
size="small"
|
||||||
|
controls-position="right"
|
||||||
|
@change="changeStyle('bar.target.size')"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
@ -4,13 +4,12 @@ import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlin
|
|||||||
import icon_adjustment_outlined from '@/assets/svg/icon_adjustment_outlined.svg'
|
import icon_adjustment_outlined from '@/assets/svg/icon_adjustment_outlined.svg'
|
||||||
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
|
import icon_edit_outlined from '@/assets/svg/icon_edit_outlined.svg'
|
||||||
import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg'
|
import icon_deleteTrash_outlined from '@/assets/svg/icon_delete-trash_outlined.svg'
|
||||||
import { ref, reactive, onMounted, onBeforeUnmount, watch, unref, computed, nextTick } from 'vue'
|
import { ref, reactive, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import CodeMirror from '@/views/visualized/data/dataset/form/CodeMirror.vue'
|
import CodeMirror from '@/views/visualized/data/dataset/form/CodeMirror.vue'
|
||||||
import { getFunction } from '@/api/dataset'
|
import { getFunction } from '@/api/dataset'
|
||||||
import { fieldType } from '@/utils/attr'
|
import { fieldType } from '@/utils/attr'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import { guid } from '@/views/visualized/data/dataset/form/util'
|
|
||||||
import { iconFieldMap } from '@/components/icon-group/field-list'
|
import { iconFieldMap } from '@/components/icon-group/field-list'
|
||||||
|
|
||||||
export interface CalcFieldType {
|
export interface CalcFieldType {
|
||||||
@ -82,7 +81,7 @@ const setNameIdTrans = (from, to, originName, name2Auto?: string[]) => {
|
|||||||
pre[next[from]] = next[to]
|
pre[next[from]] = next[to]
|
||||||
return pre
|
return pre
|
||||||
}, {})
|
}, {})
|
||||||
const on = originName.match(/\[(.+?)\]/g)
|
const on = originName.match(/\[(.+?)\]/g) || []
|
||||||
if (on) {
|
if (on) {
|
||||||
on.forEach(itm => {
|
on.forEach(itm => {
|
||||||
const ele = itm.slice(1, -1)
|
const ele = itm.slice(1, -1)
|
||||||
@ -398,10 +397,8 @@ initFunction()
|
|||||||
.mr0 {
|
.mr0 {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
|
|
||||||
:deep(.ed-select__prefix--light) {
|
:deep(.ed-select__prefix::after) {
|
||||||
padding: 0;
|
display: none;
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +75,14 @@ const init = () => {
|
|||||||
tableCell.mergeCells = tableCell.mergeCells === undefined ? false : tableCell.mergeCells
|
tableCell.mergeCells = tableCell.mergeCells === undefined ? false : tableCell.mergeCells
|
||||||
state.tableCellForm = defaultsDeep(cloneDeep(tableCell), cloneDeep(DEFAULT_TABLE_CELL))
|
state.tableCellForm = defaultsDeep(cloneDeep(tableCell), cloneDeep(DEFAULT_TABLE_CELL))
|
||||||
const alpha = props.chart.customAttr.basicStyle.alpha
|
const alpha = props.chart.customAttr.basicStyle.alpha
|
||||||
|
|
||||||
if (!isAlphaColor(state.tableCellForm.tableItemBgColor)) {
|
if (!isAlphaColor(state.tableCellForm.tableItemBgColor)) {
|
||||||
state.tableCellForm.tableItemBgColor = convertToAlphaColor(
|
state.tableCellForm.tableItemBgColor = convertToAlphaColor(
|
||||||
state.tableCellForm.tableItemBgColor,
|
state.tableCellForm.tableItemBgColor,
|
||||||
alpha
|
alpha
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAlphaColor(state.tableCellForm.tableItemSubBgColor)) {
|
if (!isAlphaColor(state.tableCellForm.tableItemSubBgColor)) {
|
||||||
state.tableCellForm.tableItemSubBgColor = convertToAlphaColor(
|
state.tableCellForm.tableItemSubBgColor = convertToAlphaColor(
|
||||||
state.tableCellForm.tableItemSubBgColor,
|
state.tableCellForm.tableItemSubBgColor,
|
||||||
@ -97,12 +99,12 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="tableCellForm" :model="state.tableCellForm" label-position="top">
|
<el-form size="small" ref="tableCellForm" :model="state.tableCellForm" label-position="top">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.backgroundColor')"
|
:label="t('chart.backgroundColor')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
v-if="showProperty('tableItemBgColor')"
|
v-if="showProperty('tableItemBgColor') && state.tableCellForm.tableItemBgColor"
|
||||||
>
|
>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -148,7 +150,7 @@ onMounted(() => {
|
|||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
label=""
|
label=""
|
||||||
v-if="showProperty('tableItemSubBgColor')"
|
v-if="showProperty('tableItemSubBgColor') && state.tableCellForm.tableItemSubBgColor"
|
||||||
>
|
>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
v-model="state.tableCellForm.tableItemSubBgColor"
|
v-model="state.tableCellForm.tableItemSubBgColor"
|
||||||
|
@ -17,7 +17,10 @@ import {
|
|||||||
S2Event,
|
S2Event,
|
||||||
S2Options,
|
S2Options,
|
||||||
TableSheet,
|
TableSheet,
|
||||||
TooltipShowOptions
|
TooltipShowOptions,
|
||||||
|
ColCell,
|
||||||
|
Node,
|
||||||
|
LayoutResult
|
||||||
} from '@antv/s2'
|
} from '@antv/s2'
|
||||||
import { ElMessageBox } from 'element-plus-secondary'
|
import { ElMessageBox } from 'element-plus-secondary'
|
||||||
import { cloneDeep, debounce, isEqual, isNumber } from 'lodash-es'
|
import { cloneDeep, debounce, isEqual, isNumber } from 'lodash-es'
|
||||||
@ -72,7 +75,7 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
if (headerGroupConfig?.columns?.length) {
|
if (headerGroupConfig?.columns?.length) {
|
||||||
const allAxis = showColumns.map(item => item.key)
|
const allAxis = showColumns.map(item => item.key)
|
||||||
const leafNodes = getLeafNodes(headerGroupConfig.columns as Array<ColumnNode>)
|
const leafNodes = getLeafNodes(headerGroupConfig.columns)
|
||||||
const leafKeys = leafNodes.map(item => item.key)
|
const leafKeys = leafNodes.map(item => item.key)
|
||||||
if (!isEqual(allAxis, leafKeys)) {
|
if (!isEqual(allAxis, leafKeys)) {
|
||||||
const { columns, meta } = headerGroupConfig
|
const { columns, meta } = headerGroupConfig
|
||||||
@ -166,6 +169,14 @@ const renderTable = (chart: ChartObj) => {
|
|||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
borderRadius: '4px'
|
borderRadius: '4px'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
interaction: {
|
||||||
|
rangeSelection: false,
|
||||||
|
resize: {
|
||||||
|
colCellHorizontal: false,
|
||||||
|
colCellVertical: false,
|
||||||
|
rowCellVertical: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s2 = new TableSheet(containerDom, s2DataConfig, s2Options)
|
s2 = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||||
@ -321,7 +332,7 @@ const renderTable = (chart: ChartObj) => {
|
|||||||
//如果有多个cell都在同一个层级,并且parent相同,那就是可以进行合并分组操作
|
//如果有多个cell都在同一个层级,并且parent相同,那就是可以进行合并分组操作
|
||||||
if (activeColumns?.length > 1) {
|
if (activeColumns?.length > 1) {
|
||||||
const sameParent = activeCells.every(
|
const sameParent = activeCells.every(
|
||||||
cell => cell.getMeta().parent === curCell.getMeta().parent
|
cell => cell.getMeta().parent.id === curCell.getMeta().parent.id
|
||||||
)
|
)
|
||||||
if (!sameParent) {
|
if (!sameParent) {
|
||||||
return
|
return
|
||||||
@ -443,6 +454,57 @@ const renderTable = (chart: ChartObj) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
s2.on(S2Event.COL_CELL_CLICK, e => {
|
||||||
|
const lastCell = s2.store.get('lastClickedCell') as ColCell
|
||||||
|
const originEvent = e.originalEvent as MouseEvent
|
||||||
|
if (!lastCell || !(originEvent?.ctrlKey || originEvent?.metaKey || originEvent?.shiftKey)) {
|
||||||
|
const cell = s2.getCell(e.target)
|
||||||
|
s2.store.set('lastClickedCell', cell)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (originEvent?.shiftKey) {
|
||||||
|
if (!lastCell) {
|
||||||
|
const cell = s2.getCell(e.target)
|
||||||
|
s2.store.set('lastClickedCell', cell)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const curCell = s2.getCell(e.target)
|
||||||
|
const lastMeta = lastCell.getMeta()
|
||||||
|
const curMeta = curCell.getMeta()
|
||||||
|
if (
|
||||||
|
lastMeta.key === curMeta.key ||
|
||||||
|
lastMeta.level !== curMeta.level ||
|
||||||
|
lastMeta.parent !== curMeta.parent
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const parent = curMeta.parent as Node
|
||||||
|
const lastIndex = parent.children.findIndex(item => item.key === lastMeta.key)
|
||||||
|
const curIndex = parent.children.findIndex(item => item.key === curMeta.key)
|
||||||
|
const startIndex = Math.min(lastIndex, curIndex)
|
||||||
|
const endIndex = Math.max(lastIndex, curIndex)
|
||||||
|
const activeCells = parent.children.slice(startIndex, endIndex + 1)
|
||||||
|
s2.interaction.clearState()
|
||||||
|
activeCells.forEach(cell => {
|
||||||
|
s2.interaction.selectHeaderCell({ cell: cell.belongsCell, isMultiSelection: true })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
s2.once(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (e: LayoutResult) => {
|
||||||
|
const initialized = s2.store.get('initialized')
|
||||||
|
if (!initialized) {
|
||||||
|
s2.store.set('initialized', true)
|
||||||
|
s2.changeSheetSize(e.colsHierarchy.width)
|
||||||
|
const length = s2.dataCfg.data?.length || 0
|
||||||
|
const headerHeight = e.colsHierarchy.height
|
||||||
|
const rowHeight = s2.options.style.cellCfg.height
|
||||||
|
const totalHeight = headerHeight + rowHeight * length
|
||||||
|
if (containerDom.offsetHeight > totalHeight) {
|
||||||
|
containerDom.style.height = totalHeight + 'px'
|
||||||
|
}
|
||||||
|
s2.render(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
s2.render()
|
s2.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,9 +548,14 @@ const getTreesMaxDepth = (nodes: Array<ColumnNode>): number => {
|
|||||||
return Math.max(...rootDepths)
|
return Math.max(...rootDepths)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resize = debounce((width, height) => {
|
const resize = debounce(height => {
|
||||||
if (s2) {
|
if (s2) {
|
||||||
s2.changeSheetSize(width, height)
|
const tableHeight = s2.container.cfg.height
|
||||||
|
if (height > tableHeight) {
|
||||||
|
const dom = document.getElementById(containerId.value)
|
||||||
|
dom.style.height = tableHeight + 'px'
|
||||||
|
}
|
||||||
|
s2.changeSheetSize(undefined, height)
|
||||||
s2.render(false)
|
s2.render(false)
|
||||||
}
|
}
|
||||||
}, 500)
|
}, 500)
|
||||||
@ -504,14 +571,13 @@ onMounted(() => {
|
|||||||
preSize[0] = size.inlineSize
|
preSize[0] = size.inlineSize
|
||||||
preSize[1] = size.blockSize
|
preSize[1] = size.blockSize
|
||||||
}
|
}
|
||||||
const widthOffset = Math.abs(size.inlineSize - preSize[0])
|
|
||||||
const heightOffset = Math.abs(size.blockSize - preSize[1])
|
const heightOffset = Math.abs(size.blockSize - preSize[1])
|
||||||
if (widthOffset < TOLERANCE && heightOffset < TOLERANCE) {
|
if (heightOffset < TOLERANCE) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
preSize[0] = size.inlineSize
|
preSize[0] = size.inlineSize
|
||||||
preSize[1] = size.blockSize
|
preSize[1] = size.blockSize
|
||||||
resize(size.inlineSize, Math.round(size.blockSize))
|
resize(Math.round(size.blockSize))
|
||||||
})
|
})
|
||||||
resizeObserver.observe(document.getElementById(containerId.value))
|
resizeObserver.observe(document.getElementById(containerId.value))
|
||||||
})
|
})
|
||||||
@ -536,6 +602,8 @@ class GroupMenu extends BaseTooltip {
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40vh;
|
height: 40vh;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group-menu {
|
.group-menu {
|
||||||
|
@ -9,11 +9,12 @@ import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
|||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_TABLE_HEADER } from '@/views/chart/components/editor/util/chart'
|
import { COLOR_PANEL, DEFAULT_TABLE_HEADER } from '@/views/chart/components/editor/util/chart'
|
||||||
import { ElDivider, ElSpace } from 'element-plus-secondary'
|
import { ElDivider, ElSpace } from 'element-plus-secondary'
|
||||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
import { cloneDeep, defaultsDeep, isEqual } from 'lodash-es'
|
||||||
import { convertToAlphaColor, isAlphaColor } from '@/views/chart/components/js/util'
|
import { convertToAlphaColor, isAlphaColor } from '@/views/chart/components/js/util'
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import TableHeaderGroupConfig from './TableHeaderGroupConfig.vue'
|
import TableHeaderGroupConfig from './TableHeaderGroupConfig.vue'
|
||||||
|
import { getLeafNodes } from '@/views/chart/components/js/panel/common/common_table'
|
||||||
|
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
const { batchOptStatus, mobileInPc } = storeToRefs(dvMainStore)
|
const { batchOptStatus, mobileInPc } = storeToRefs(dvMainStore)
|
||||||
@ -86,6 +87,28 @@ const enableGroupConfig = computed(() => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const groupConfigValid = computed(() => {
|
||||||
|
const columns = props.chart?.customAttr?.tableHeader?.headerGroupConfig?.columns
|
||||||
|
if (!columns?.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const noGroup = columns.every(item => !item.children?.length)
|
||||||
|
if (noGroup) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const xAxis = props.chart.xAxis
|
||||||
|
const showColumns = []
|
||||||
|
xAxis?.forEach(axis => {
|
||||||
|
axis.hide !== true && showColumns.push({ key: axis.dataeaseName })
|
||||||
|
})
|
||||||
|
if (!showColumns.length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const allAxis = showColumns.map(item => item.key)
|
||||||
|
const leafNodes = getLeafNodes(columns as Array<ColumnNode>)
|
||||||
|
const leafKeys = leafNodes.map(item => item.key)
|
||||||
|
return isEqual(allAxis, leafKeys)
|
||||||
|
})
|
||||||
const init = () => {
|
const init = () => {
|
||||||
const tableHeader = props.chart?.customAttr?.tableHeader
|
const tableHeader = props.chart?.customAttr?.tableHeader
|
||||||
if (tableHeader) {
|
if (tableHeader) {
|
||||||
@ -128,6 +151,7 @@ onMounted(() => {
|
|||||||
:disabled="!state.tableHeaderForm.showTableHeader"
|
:disabled="!state.tableHeaderForm.showTableHeader"
|
||||||
ref="tableHeaderForm"
|
ref="tableHeaderForm"
|
||||||
label-position="top"
|
label-position="top"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="
|
:label="
|
||||||
@ -135,7 +159,7 @@ onMounted(() => {
|
|||||||
"
|
"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
v-if="showProperty('tableHeaderBgColor')"
|
v-if="showProperty('tableHeaderBgColor') && state.tableHeaderForm.tableHeaderBgColor"
|
||||||
>
|
>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
@ -742,6 +766,20 @@ onMounted(() => {
|
|||||||
{{ t('chart.table_header_show_vertical_border') }}
|
{{ t('chart.table_header_show_vertical_border') }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
class="form-item"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
v-if="showProperty('rowHeaderFreeze')"
|
||||||
|
>
|
||||||
|
<el-checkbox
|
||||||
|
size="small"
|
||||||
|
:effect="themes"
|
||||||
|
v-model="state.tableHeaderForm.rowHeaderFreeze"
|
||||||
|
@change="changeTableHeader('rowHeaderFreeze')"
|
||||||
|
>
|
||||||
|
{{ t('chart.table_row_header_freeze') }}
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="!batchOptStatus && showProperty('headerGroup')"
|
v-if="!batchOptStatus && showProperty('headerGroup')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
@ -761,7 +799,7 @@ onMounted(() => {
|
|||||||
<div class="header-group-config">
|
<div class="header-group-config">
|
||||||
<span>{{ t('chart.table_header_group_config') }}</span>
|
<span>{{ t('chart.table_header_group_config') }}</span>
|
||||||
<div class="group-icon">
|
<div class="group-icon">
|
||||||
<span v-if="state.tableHeaderForm.headerGroupConfig?.columns?.length">
|
<span v-if="groupConfigValid">
|
||||||
{{ t('visualization.already_setting') }}
|
{{ t('visualization.already_setting') }}
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, PropType, reactive, watch, ref, inject, nextTick } from 'vue'
|
import { onMounted, PropType, reactive, watch, ref, inject, nextTick, computed } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import {
|
import {
|
||||||
DEFAULT_BASIC_STYLE,
|
DEFAULT_BASIC_STYLE,
|
||||||
@ -32,6 +32,7 @@ watch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
const aggregations = [
|
const aggregations = [
|
||||||
|
{ name: t('chart.none'), value: 'NONE' },
|
||||||
{ name: t('chart.sum'), value: 'SUM' },
|
{ name: t('chart.sum'), value: 'SUM' },
|
||||||
{ name: t('chart.avg'), value: 'AVG' },
|
{ name: t('chart.avg'), value: 'AVG' },
|
||||||
{ name: t('chart.max'), value: 'MAX' },
|
{ name: t('chart.max'), value: 'MAX' },
|
||||||
@ -53,6 +54,26 @@ const state = reactive({
|
|||||||
basicStyleForm: JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
basicStyleForm: JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const showColFieldTotalLabel = computed(() => {
|
||||||
|
const chart = props.chart
|
||||||
|
return (
|
||||||
|
chart.customAttr.basicStyle.quotaPosition !== 'row' &&
|
||||||
|
chart.xAxisExt.length &&
|
||||||
|
chart.yAxis.length > 1
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const showRowFieldTotalLabel = computed(() => {
|
||||||
|
const chart = props.chart
|
||||||
|
return (
|
||||||
|
chart.customAttr.basicStyle.quotaPosition === 'row' &&
|
||||||
|
chart.customAttr.basicStyle.tableLayoutMode !== 'tree' &&
|
||||||
|
chart.xAxis.length &&
|
||||||
|
chart.xAxisExt.length &&
|
||||||
|
chart.yAxis.length > 1
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
function onSelectedSubTotalDimensionNameChange(name) {
|
function onSelectedSubTotalDimensionNameChange(name) {
|
||||||
state.selectedSubTotalDimension = find(state.subTotalDimensionList, d => d.name === name)
|
state.selectedSubTotalDimension = find(state.subTotalDimensionList, d => d.name === name)
|
||||||
}
|
}
|
||||||
@ -159,6 +180,7 @@ const init = () => {
|
|||||||
total.dataeaseName = totalCfg[0].dataeaseName
|
total.dataeaseName = totalCfg[0].dataeaseName
|
||||||
total.aggregation = totalCfg[0].aggregation
|
total.aggregation = totalCfg[0].aggregation
|
||||||
total.originName = totalCfg[0].originName
|
total.originName = totalCfg[0].originName
|
||||||
|
total.label = totalCfg[0].label
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -174,6 +196,7 @@ const changeTotal = (totalItem, totals) => {
|
|||||||
if (item.dataeaseName === totalItem.dataeaseName) {
|
if (item.dataeaseName === totalItem.dataeaseName) {
|
||||||
totalItem.aggregation = item.aggregation
|
totalItem.aggregation = item.aggregation
|
||||||
totalItem.originName = item.originName
|
totalItem.originName = item.originName
|
||||||
|
totalItem.label = item.label
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,6 +206,7 @@ const changeTotalAggr = (totalItem, totals, colOrNum) => {
|
|||||||
const item = totals[i]
|
const item = totals[i]
|
||||||
if (item.dataeaseName === totalItem.dataeaseName) {
|
if (item.dataeaseName === totalItem.dataeaseName) {
|
||||||
item.aggregation = totalItem.aggregation
|
item.aggregation = totalItem.aggregation
|
||||||
|
item.label = totalItem.label
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,7 +220,8 @@ const setupTotalCfg = (totalCfg, axis) => {
|
|||||||
axis.forEach(i => {
|
axis.forEach(i => {
|
||||||
totalCfg.push({
|
totalCfg.push({
|
||||||
dataeaseName: i.dataeaseName,
|
dataeaseName: i.dataeaseName,
|
||||||
aggregation: 'SUM'
|
aggregation: 'SUM',
|
||||||
|
label: i.chartShowName ?? i.name
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@ -214,7 +239,10 @@ const setupTotalCfg = (totalCfg, axis) => {
|
|||||||
totalCfg.push({
|
totalCfg.push({
|
||||||
dataeaseName: i.dataeaseName,
|
dataeaseName: i.dataeaseName,
|
||||||
aggregation: cfgMap[i.dataeaseName] ? cfgMap[i.dataeaseName].aggregation : 'SUM',
|
aggregation: cfgMap[i.dataeaseName] ? cfgMap[i.dataeaseName].aggregation : 'SUM',
|
||||||
originName: cfgMap[i.dataeaseName] ? cfgMap[i.dataeaseName].originName : ''
|
originName: cfgMap[i.dataeaseName] ? cfgMap[i.dataeaseName].originName : '',
|
||||||
|
label: cfgMap[i.dataeaseName]?.label
|
||||||
|
? cfgMap[i.dataeaseName].label
|
||||||
|
: i.chartShowName ?? i.name
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -264,7 +292,7 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="tableTotalForm" :model="state.tableTotalForm" label-position="top">
|
<el-form size="small" ref="tableTotalForm" :model="state.tableTotalForm" label-position="top">
|
||||||
<el-divider
|
<el-divider
|
||||||
v-if="showProperty('row')"
|
v-if="showProperty('row')"
|
||||||
content-position="center"
|
content-position="center"
|
||||||
@ -302,13 +330,13 @@ onMounted(() => {
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.total_label')"
|
:label="t('chart.table_grand_total_label')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
:placeholder="t('chart.total_label')"
|
:placeholder="t('chart.table_grand_total_label')"
|
||||||
size="small"
|
size="small"
|
||||||
maxlength="20"
|
maxlength="20"
|
||||||
v-model="state.tableTotalForm.row.label"
|
v-model="state.tableTotalForm.row.label"
|
||||||
@ -371,6 +399,28 @@ onMounted(() => {
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="showRowFieldTotalLabel"
|
||||||
|
class="form-item"
|
||||||
|
:label="t('chart.table_field_total_label')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
:effect="themes"
|
||||||
|
:placeholder="t('chart.table_field_total_label')"
|
||||||
|
size="small"
|
||||||
|
maxlength="20"
|
||||||
|
v-model="state.rowTotalItem.label"
|
||||||
|
clearable
|
||||||
|
@change="
|
||||||
|
changeTotalAggr(
|
||||||
|
state.rowTotalItem,
|
||||||
|
state.tableTotalForm.row.calcTotals.cfg,
|
||||||
|
'row.calcTotals.cfg'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="chart.type === 'table-pivot'"
|
v-if="chart.type === 'table-pivot'"
|
||||||
:label="t('chart.total_sort')"
|
:label="t('chart.total_sort')"
|
||||||
@ -469,7 +519,7 @@ onMounted(() => {
|
|||||||
<el-radio-group
|
<el-radio-group
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
v-model="state.tableTotalForm.row.reverseSubLayout"
|
v-model="state.tableTotalForm.row.reverseSubLayout"
|
||||||
:disabled="chart.xAxis.length < 2"
|
:disabled="chart.xAxis.length < 2 || state.basicStyleForm.tableLayoutMode === 'tree'"
|
||||||
@change="changeTableTotal('row')"
|
@change="changeTableTotal('row')"
|
||||||
>
|
>
|
||||||
<el-radio :effect="themes" :label="true">{{ t('chart.total_pos_top') }}</el-radio>
|
<el-radio :effect="themes" :label="true">{{ t('chart.total_pos_top') }}</el-radio>
|
||||||
@ -587,13 +637,13 @@ onMounted(() => {
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
:label="t('chart.total_label')"
|
:label="t('chart.table_grand_total_label')"
|
||||||
class="form-item"
|
class="form-item"
|
||||||
:class="'form-item-' + themes"
|
:class="'form-item-' + themes"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
:effect="themes"
|
:effect="themes"
|
||||||
:placeholder="t('chart.total_label')"
|
:placeholder="t('chart.table_grand_total_label')"
|
||||||
size="small"
|
size="small"
|
||||||
maxlength="20"
|
maxlength="20"
|
||||||
v-model="state.tableTotalForm.col.label"
|
v-model="state.tableTotalForm.col.label"
|
||||||
@ -656,6 +706,28 @@ onMounted(() => {
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item
|
||||||
|
v-if="showColFieldTotalLabel"
|
||||||
|
class="form-item"
|
||||||
|
:label="t('chart.table_field_total_label')"
|
||||||
|
:class="'form-item-' + themes"
|
||||||
|
>
|
||||||
|
<el-input
|
||||||
|
:effect="themes"
|
||||||
|
:placeholder="t('chart.table_field_total_label')"
|
||||||
|
size="small"
|
||||||
|
maxlength="20"
|
||||||
|
v-model="state.colTotalItem.label"
|
||||||
|
clearable
|
||||||
|
@change="
|
||||||
|
changeTotalAggr(
|
||||||
|
state.colTotalItem,
|
||||||
|
state.tableTotalForm.col.calcTotals.cfg,
|
||||||
|
'col.calcTotals.cfg'
|
||||||
|
)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item
|
||||||
v-if="chart.type === 'table-pivot'"
|
v-if="chart.type === 'table-pivot'"
|
||||||
:label="t('chart.total_sort')"
|
:label="t('chart.total_sort')"
|
||||||
|
@ -100,7 +100,7 @@ defineExpose({
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
<style lang="less" scoped>
|
<style lang="less">
|
||||||
.filter-tree-cont {
|
.filter-tree-cont {
|
||||||
.tree-cont {
|
.tree-cont {
|
||||||
min-height: 67px;
|
min-height: 67px;
|
||||||
|
@ -493,6 +493,7 @@ const emits = defineEmits(['update:item', 'del'])
|
|||||||
<span class="filed-title">{{ t('auth.screen_method') }}</span>
|
<span class="filed-title">{{ t('auth.screen_method') }}</span>
|
||||||
<el-select
|
<el-select
|
||||||
size="small"
|
size="small"
|
||||||
|
class="w181"
|
||||||
@change="filterTypeChange"
|
@change="filterTypeChange"
|
||||||
v-model="item.filterType"
|
v-model="item.filterType"
|
||||||
:placeholder="t('auth.select')"
|
:placeholder="t('auth.select')"
|
||||||
@ -748,7 +749,6 @@ const emits = defineEmits(['update:item', 'del'])
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #ffffff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ed-input {
|
.ed-input {
|
||||||
@ -756,11 +756,15 @@ const emits = defineEmits(['update:item', 'del'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
.w100.ed-select {
|
.w100.ed-select {
|
||||||
width: 100px;
|
width: 100px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w181.ed-select {
|
||||||
|
width: 181px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w70 {
|
.w70 {
|
||||||
width: 70px;
|
width: 70px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mar5 {
|
.mar5 {
|
||||||
@ -849,7 +853,7 @@ const emits = defineEmits(['update:item', 'del'])
|
|||||||
background-color: #212121;
|
background-color: #212121;
|
||||||
border: 1px solid #5f5f5f;
|
border: 1px solid #5f5f5f;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
box-shadow: none;
|
box-shadow: none !important;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
font-family: var(--de-custom_font, 'PingFang');
|
font-family: var(--de-custom_font, 'PingFang');
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
@ -246,5 +246,4 @@ const del = (index, child) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -375,6 +375,7 @@ const emits = defineEmits(['update:item', 'del'])
|
|||||||
size="small"
|
size="small"
|
||||||
@change="filterTypeChange"
|
@change="filterTypeChange"
|
||||||
v-model="item.filterType"
|
v-model="item.filterType"
|
||||||
|
class="w181"
|
||||||
:placeholder="t('auth.select')"
|
:placeholder="t('auth.select')"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
@ -586,11 +587,15 @@ const emits = defineEmits(['update:item', 'del'])
|
|||||||
}
|
}
|
||||||
|
|
||||||
.w100.ed-select {
|
.w100.ed-select {
|
||||||
width: 100px;
|
width: 100px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w181.ed-select {
|
||||||
|
width: 181px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w70 {
|
.w70 {
|
||||||
width: 70px;
|
width: 70px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mar5 {
|
.mar5 {
|
||||||
@ -676,11 +681,12 @@ const emits = defineEmits(['update:item', 'del'])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ed-input__wrapper) {
|
:deep(.ed-input__wrapper),
|
||||||
|
:deep(.ed-select__wrapper) {
|
||||||
background-color: #f8f8fa;
|
background-color: #f8f8fa;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
box-shadow: none;
|
box-shadow: none !important;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
font-family: var(--de-custom_font, 'PingFang');
|
font-family: var(--de-custom_font, 'PingFang');
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
@ -55,13 +55,12 @@ import SortPriorityEdit from '@/views/chart/components/editor/drag-item/componen
|
|||||||
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
||||||
import CalcFieldEdit from '@/views/visualized/data/dataset/form/CalcFieldEdit.vue'
|
import CalcFieldEdit from '@/views/visualized/data/dataset/form/CalcFieldEdit.vue'
|
||||||
import { getFieldName, guid } from '@/views/visualized/data/dataset/form/util'
|
import { getFieldName, guid } from '@/views/visualized/data/dataset/form/util'
|
||||||
import { cloneDeep, forEach, get } from 'lodash-es'
|
import { cloneDeep, forEach, get, debounce, set, concat, keys } from 'lodash-es'
|
||||||
import { deleteField, saveField } from '@/api/dataset'
|
import { deleteField, saveField } from '@/api/dataset'
|
||||||
import { getWorldTree, listCustomGeoArea } from '@/api/map'
|
import { getWorldTree, listCustomGeoArea } from '@/api/map'
|
||||||
import chartViewManager from '@/views/chart/components/js/panel'
|
import chartViewManager from '@/views/chart/components/js/panel'
|
||||||
import DatasetSelect from '@/views/chart/components/editor/dataset-select/DatasetSelect.vue'
|
import DatasetSelect from '@/views/chart/components/editor/dataset-select/DatasetSelect.vue'
|
||||||
import { useDraggable } from '@vueuse/core'
|
import { useDraggable } from '@vueuse/core'
|
||||||
import { set, concat, keys } from 'lodash-es'
|
|
||||||
import { PluginComponent } from '@/components/plugin'
|
import { PluginComponent } from '@/components/plugin'
|
||||||
import { Field, getFieldByDQ, copyChartField, deleteChartField } from '@/api/chart'
|
import { Field, getFieldByDQ, copyChartField, deleteChartField } from '@/api/chart'
|
||||||
import ChartTemplateInfo from '@/views/chart/components/editor/common/ChartTemplateInfo.vue'
|
import ChartTemplateInfo from '@/views/chart/components/editor/common/ChartTemplateInfo.vue'
|
||||||
@ -104,6 +103,10 @@ const { emitter } = useEmitt({
|
|||||||
name: 'set-table-column-width',
|
name: 'set-table-column-width',
|
||||||
callback: args => onTableColumnWidthChange(args)
|
callback: args => onTableColumnWidthChange(args)
|
||||||
})
|
})
|
||||||
|
useEmitt({
|
||||||
|
name: 'set-page-size',
|
||||||
|
callback: args => onTablePageSizeChange(args)
|
||||||
|
})
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
view: {
|
view: {
|
||||||
type: Object as PropType<ChartObj>,
|
type: Object as PropType<ChartObj>,
|
||||||
@ -171,11 +174,15 @@ const editComponentName = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const toolTip = computed(() => {
|
const toolTip = computed(() => {
|
||||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
return props.themes || 'dark'
|
||||||
})
|
})
|
||||||
|
|
||||||
const templateStatusShow = computed(() => {
|
const templateStatusShow = computed(() => {
|
||||||
return view.value['dataFrom'] === 'template' && !mobileInPc.value
|
return (
|
||||||
|
view.value['dataFrom'] === 'template' &&
|
||||||
|
view.value.type !== 'picture-group' &&
|
||||||
|
!mobileInPc.value
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const { view } = toRefs(props)
|
const { view } = toRefs(props)
|
||||||
@ -208,7 +215,7 @@ const isDataEaseBi = computed(() => appStore.getIsDataEaseBi || appStore.getIsIf
|
|||||||
const itemFormRules = reactive<FormRules>({
|
const itemFormRules = reactive<FormRules>({
|
||||||
chartShowName: [
|
chartShowName: [
|
||||||
{ required: true, message: t('commons.input_content'), trigger: 'change' },
|
{ required: true, message: t('commons.input_content'), trigger: 'change' },
|
||||||
{ max: 50, message: t('commons.char_can_not_more_50'), trigger: 'change' }
|
{ max: 200, message: t('commons.char_count_limit', { count: 200 }), trigger: 'change' }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -915,8 +922,17 @@ const calcData = (view, resetDrill = false, updateQuery = '') => {
|
|||||||
}
|
}
|
||||||
if (resetDrill) {
|
if (resetDrill) {
|
||||||
useEmitt().emitter.emit('resetDrill-' + view.id, 0)
|
useEmitt().emitter.emit('resetDrill-' + view.id, 0)
|
||||||
|
} else {
|
||||||
|
if (mobileInPc.value) {
|
||||||
|
//移动端设计
|
||||||
|
useEmitt().emitter.emit('onMobileStatusChange', {
|
||||||
|
type: 'componentStyleChange',
|
||||||
|
value: { type: 'calcData', component: JSON.parse(JSON.stringify(view)) }
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
useEmitt().emitter.emit('calcData-' + view.id, view)
|
useEmitt().emitter.emit('calcData-' + view.id, view)
|
||||||
|
snapshotStore.recordSnapshotCache('renderChart', view.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
snapshotStore.recordSnapshotCache('calcData', view.id)
|
snapshotStore.recordSnapshotCache('calcData', view.id)
|
||||||
if (updateQuery === 'updateQuery') {
|
if (updateQuery === 'updateQuery') {
|
||||||
@ -1026,12 +1042,13 @@ const onTypeChange = (render, type) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onBasicStyleChange = (chartForm: ChartEditorForm<ChartBasicStyle>, prop: string) => {
|
const onBasicStyleChange = (chartForm: ChartEditorForm<ChartBasicStyle>, prop: string) => {
|
||||||
const { data, requestData } = chartForm
|
const { data, requestData, render } = chartForm
|
||||||
const val = get(data, prop)
|
const val = get(data, prop)
|
||||||
set(view.value.customAttr.basicStyle, prop, val)
|
set(view.value.customAttr.basicStyle, prop, val)
|
||||||
if (requestData) {
|
if (requestData) {
|
||||||
calcData(view.value)
|
calcData(view.value)
|
||||||
} else {
|
}
|
||||||
|
if (render !== false) {
|
||||||
renderChart(view.value)
|
renderChart(view.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1064,7 +1081,7 @@ const onMiscChange = val => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onLabelChange = (chartForm: ChartEditorForm<ChartLabelAttr>, prop: string) => {
|
const onLabelChange = (chartForm: ChartEditorForm<ChartLabelAttr>, prop: string) => {
|
||||||
const { data, requestData, render } = chartForm
|
const { data, render } = chartForm
|
||||||
let labelObj = data
|
let labelObj = data
|
||||||
if (!data) {
|
if (!data) {
|
||||||
labelObj = chartForm as unknown as ChartLabelAttr
|
labelObj = chartForm as unknown as ChartLabelAttr
|
||||||
@ -1250,6 +1267,14 @@ const onTableColumnWidthChange = val => {
|
|||||||
snapshotStore.recordSnapshotCache('renderChart', view.value.id)
|
snapshotStore.recordSnapshotCache('renderChart', view.value.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onTablePageSizeChange = val => {
|
||||||
|
if (editMode.value !== 'edit') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
view.value.customAttr.basicStyle.tablePageSize = val
|
||||||
|
snapshotStore.recordSnapshotCache('renderChart', view.value.id)
|
||||||
|
}
|
||||||
|
|
||||||
const onExtTooltipChange = val => {
|
const onExtTooltipChange = val => {
|
||||||
view.value.extTooltip = val
|
view.value.extTooltip = val
|
||||||
}
|
}
|
||||||
@ -1504,13 +1529,18 @@ const addDsWindow = () => {
|
|||||||
const editDs = () => {
|
const editDs = () => {
|
||||||
const path =
|
const path =
|
||||||
embeddedStore.getToken && appStore.getIsIframe ? 'dataset-embedded-form' : '/dataset-form'
|
embeddedStore.getToken && appStore.getIsIframe ? 'dataset-embedded-form' : '/dataset-form'
|
||||||
|
const openType = wsCache.get('open-backend') === '1' ? '_self' : '_blank'
|
||||||
|
// 此处校验提前 防止router返回时找到错误的路径
|
||||||
|
if (openType === '_self' && !dvInfo.value.id) {
|
||||||
|
ElMessage.warning(t('visualization.save_page_tips'))
|
||||||
|
return
|
||||||
|
}
|
||||||
let routeData = router.resolve({
|
let routeData = router.resolve({
|
||||||
path: path,
|
path: path,
|
||||||
query: {
|
query: {
|
||||||
id: view.value.tableId
|
id: view.value.tableId
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const openType = wsCache.get('open-backend') === '1' ? '_self' : '_blank'
|
|
||||||
// 检查是否保存
|
// 检查是否保存
|
||||||
if (openType === '_self') {
|
if (openType === '_self') {
|
||||||
if (!dvInfo.value.id) {
|
if (!dvInfo.value.id) {
|
||||||
@ -1518,6 +1548,7 @@ const editDs = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
canvasSave(() => {
|
canvasSave(() => {
|
||||||
|
wsCache.delete('DE-DV-CATCH-' + dvInfo.value.id)
|
||||||
const newWindow = window.open(routeData.href, openType)
|
const newWindow = window.open(routeData.href, openType)
|
||||||
initOpenHandler(newWindow)
|
initOpenHandler(newWindow)
|
||||||
})
|
})
|
||||||
@ -1575,6 +1606,7 @@ const closeSortPriority = () => {
|
|||||||
}
|
}
|
||||||
const saveSortPriority = () => {
|
const saveSortPriority = () => {
|
||||||
view.value.sortPriority = state.sortPriority as ChartViewField[]
|
view.value.sortPriority = state.sortPriority as ChartViewField[]
|
||||||
|
recordSnapshotInfo('render')
|
||||||
closeSortPriority()
|
closeSortPriority()
|
||||||
}
|
}
|
||||||
const onPriorityChange = val => {
|
const onPriorityChange = val => {
|
||||||
@ -1710,14 +1742,14 @@ const { y, isDragging } = useDraggable(el, {
|
|||||||
draggingElement: elDrag
|
draggingElement: elDrag
|
||||||
})
|
})
|
||||||
const previewHeight = ref(0)
|
const previewHeight = ref(0)
|
||||||
const calcEle = () => {
|
const calcEle = debounce(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
previewHeight.value = (elDrag.value as HTMLDivElement).offsetHeight
|
previewHeight.value = (elDrag.value as HTMLDivElement).offsetHeight
|
||||||
y.value = previewHeight.value / 2 + 200
|
y.value = previewHeight.value / 2 + 200
|
||||||
})
|
})
|
||||||
}
|
}, 500)
|
||||||
|
|
||||||
const setCacheId = () => {
|
const setCacheId = debounce(() => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
// 富文本不使用cacheId
|
// 富文本不使用cacheId
|
||||||
if (
|
if (
|
||||||
@ -1729,7 +1761,7 @@ const setCacheId = () => {
|
|||||||
return
|
return
|
||||||
view.value.tableId = cacheId as unknown as number
|
view.value.tableId = cacheId as unknown as number
|
||||||
})
|
})
|
||||||
}
|
}, 500)
|
||||||
watch(
|
watch(
|
||||||
() => curComponent.value,
|
() => curComponent.value,
|
||||||
val => {
|
val => {
|
||||||
@ -1831,7 +1863,7 @@ const setActiveShift = (ele, type = 'dimension') => {
|
|||||||
|
|
||||||
const isDrag = ref(false)
|
const isDrag = ref(false)
|
||||||
|
|
||||||
const dragStartD = (e: DragEvent) => {
|
const dragStartD = () => {
|
||||||
isDrag.value = true
|
isDrag.value = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
isDraggingItem.value = true
|
isDraggingItem.value = true
|
||||||
@ -1848,7 +1880,7 @@ const singleDragStartD = (e: DragEvent, ele, type) => {
|
|||||||
startToMove(e, unref(activeDimension.value))
|
startToMove(e, unref(activeDimension.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
const dragStart = (e: DragEvent) => {
|
const dragStart = () => {
|
||||||
isDrag.value = true
|
isDrag.value = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
isDraggingItem.value = true
|
isDraggingItem.value = true
|
||||||
@ -2040,10 +2072,10 @@ const deleteChartFieldItem = id => {
|
|||||||
><Icon><dvInfoSvg class="svg-icon" /></Icon
|
><Icon><dvInfoSvg class="svg-icon" /></Icon
|
||||||
></el-icon>
|
></el-icon>
|
||||||
</template>
|
</template>
|
||||||
<div style="margin-bottom: 4px; font-size: 14px; color: #fff">
|
<div style="margin-bottom: 4px; font-size: 14px; color: #646a73">
|
||||||
{{ t('visualization.view_id') }}
|
{{ t('visualization.view_id') }}
|
||||||
</div>
|
</div>
|
||||||
<div style="font-size: 14px; color: #fff">
|
<div style="font-size: 14px; color: #1f2329">
|
||||||
{{ view.id }}
|
{{ view.id }}
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
@ -3828,7 +3860,7 @@ const deleteChartFieldItem = id => {
|
|||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<chart-template-info v-if="templateStatusShow"></chart-template-info>
|
<chart-template-info v-if="templateStatusShow" :themes="themes"></chart-template-info>
|
||||||
<!--显示名修改-->
|
<!--显示名修改-->
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="state.renameItem"
|
v-model="state.renameItem"
|
||||||
@ -4111,11 +4143,11 @@ const deleteChartFieldItem = id => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.editor-light {
|
.editor-light {
|
||||||
border-left: solid 1px @side-outline-border-color-light;
|
border-left: solid 1px @side-outline-border-color-light !important;
|
||||||
color: @canvas-main-font-color-light;
|
color: @canvas-main-font-color-light!important;
|
||||||
background-color: @side-area-background-light;
|
background-color: @side-area-background-light!important;
|
||||||
:deep(.ed-tabs__header) {
|
:deep(.ed-tabs__header) {
|
||||||
border-top: solid 1px @side-outline-border-color-light;
|
border-top: solid 1px @side-outline-border-color-light !important;
|
||||||
}
|
}
|
||||||
:deep(.drag_main_area) {
|
:deep(.drag_main_area) {
|
||||||
border-top: solid 1px @side-outline-border-color-light !important;
|
border-top: solid 1px @side-outline-border-color-light !important;
|
||||||
@ -4130,7 +4162,7 @@ const deleteChartFieldItem = id => {
|
|||||||
border-top: 1px solid @side-outline-border-color-light !important;
|
border-top: 1px solid @side-outline-border-color-light !important;
|
||||||
}
|
}
|
||||||
:deep(.dataset-main) {
|
:deep(.dataset-main) {
|
||||||
border-left: 1px solid @side-outline-border-color-light;
|
border-left: 1px solid @side-outline-border-color-light !important;
|
||||||
}
|
}
|
||||||
:deep(input) {
|
:deep(input) {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -4140,14 +4172,14 @@ const deleteChartFieldItem = id => {
|
|||||||
background-color: @side-outline-border-color-light !important;
|
background-color: @side-outline-border-color-light !important;
|
||||||
}
|
}
|
||||||
:deep(.item-span-style) {
|
:deep(.item-span-style) {
|
||||||
color: @canvas-main-font-color-light;
|
color: @canvas-main-font-color-light!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.editor-title) {
|
:deep(.editor-title) {
|
||||||
color: #1f2329;
|
color: #1f2329 !important;
|
||||||
}
|
}
|
||||||
:deep(.collapse-title) {
|
:deep(.collapse-title) {
|
||||||
color: #1f2329;
|
color: #1f2329 !important;
|
||||||
}
|
}
|
||||||
:deep(.collapse-icon) {
|
:deep(.collapse-icon) {
|
||||||
color: #646a73 !important;
|
color: #646a73 !important;
|
||||||
@ -4214,7 +4246,7 @@ const deleteChartFieldItem = id => {
|
|||||||
|
|
||||||
// editor form 全局样式
|
// editor form 全局样式
|
||||||
.editor-dark {
|
.editor-dark {
|
||||||
border-left: solid 1px @main-collapse-border-dark;
|
border-left: solid 1px @main-collapse-border-dark !important;
|
||||||
.dataset-selector {
|
.dataset-selector {
|
||||||
:deep(.ed-input__inner),
|
:deep(.ed-input__inner),
|
||||||
:deep(.ed-input__wrapper),
|
:deep(.ed-input__wrapper),
|
||||||
@ -4227,12 +4259,10 @@ const deleteChartFieldItem = id => {
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
:deep(.ed-input__wrapper) {
|
:deep(.ed-input__wrapper) {
|
||||||
box-shadow: none;
|
box-shadow: 0 0 0 1px hsla(0, 0%, 100%, 0.15) inset !important;
|
||||||
border: 1px solid #636363;
|
|
||||||
}
|
}
|
||||||
:deep(.ed-input__wrapper:hover) {
|
:deep(.ed-input__wrapper:hover) {
|
||||||
box-shadow: none;
|
box-shadow: 0 0 0 1px var(--ed-color-primary, #3370ff) inset !important;
|
||||||
border: 1px solid #3370ff;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.query-style-tab {
|
.query-style-tab {
|
||||||
@ -4316,63 +4346,8 @@ span {
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
:deep(.ed-collapse-item__header) {
|
|
||||||
height: 36px !important;
|
|
||||||
line-height: 36px !important;
|
|
||||||
font-size: 12px !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
font-weight: 500 !important;
|
|
||||||
border-top: unset;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
border-bottom-color: var(--ed-collapse-border-color);
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ed-collapse-item__arrow {
|
|
||||||
margin: 0 6px 0 8px;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
color: #A6A6A6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ed-collapse-item__content) {
|
:deep(.ed-collapse-item__content) {
|
||||||
padding: 16px 10px 0;
|
padding: 16px 10px 0;
|
||||||
border: none;
|
|
||||||
:deep(.ed-checkbox) {
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
.ed-checkbox {
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.style-dark) {
|
|
||||||
.ed-collapse-item__header {
|
|
||||||
&.is-active {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ed-collapse-item__arrow {
|
|
||||||
&.is-active {
|
|
||||||
color: #a6a6a6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
:deep(.ed-collapse-item.ed-collapse--dark .ed-collapse-item__header) {
|
|
||||||
border-color: rgba(255, 255, 255, 0.15);
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.ed-collapse-item__arrow {
|
|
||||||
&.is-active {
|
|
||||||
color: #a6a6a6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4397,11 +4372,14 @@ span {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 0 8px !important;
|
padding: 0 8px !important;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ed-tabs__item:not(.is-active)) {
|
||||||
color: var(--custom-tab-color);
|
color: var(--custom-tab-color);
|
||||||
}
|
}
|
||||||
:deep(.is-active) {
|
|
||||||
|
:deep(.ed-tabs__item.is-active) {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--ed-color-primary, #3370ff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ed-tabs__nav-scroll) {
|
:deep(.ed-tabs__nav-scroll) {
|
||||||
@ -4736,6 +4714,7 @@ span {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
width: calc(100% - 24px);
|
width: calc(100% - 24px);
|
||||||
@ -4771,7 +4750,7 @@ span {
|
|||||||
.result-style-dark {
|
.result-style-dark {
|
||||||
:deep(.ed-button) {
|
:deep(.ed-button) {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
background-color: #0089ff !important;
|
background-color: var(--ed-color-primary, #3370ff);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
@ -4807,7 +4786,6 @@ span {
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
background-color: #0089ff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.switch-chart-dark {
|
.switch-chart-dark {
|
||||||
@ -4831,7 +4809,7 @@ span {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
color: #fff;
|
color: #1f2329;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
&.dark {
|
&.dark {
|
||||||
@ -5085,6 +5063,7 @@ span {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
z-index: 1000;
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||||
}
|
}
|
||||||
.style-collapse {
|
.style-collapse {
|
||||||
@ -5121,7 +5100,7 @@ span {
|
|||||||
.field-setting {
|
.field-setting {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
color: #a6a6a6;
|
color: #646a73;
|
||||||
&.remove-icon--dark {
|
&.remove-icon--dark {
|
||||||
color: #a6a6a6;
|
color: #a6a6a6;
|
||||||
}
|
}
|
||||||
@ -5160,10 +5139,13 @@ span {
|
|||||||
.chart-type-select {
|
.chart-type-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
:deep(.ed-input__prefix-inner > div) {
|
:deep(.ed-select__prefix) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: none;
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
height: 20px;
|
||||||
.chart-type-select-icon {
|
.chart-type-select-icon {
|
||||||
width: 23px;
|
width: 23px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
@ -5211,6 +5193,9 @@ span {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
.ed-dropdown__popper.ed-popper.is-dark:has(.dark-dimension-quota) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
:deep(.ed-select-dropdown__item) {
|
:deep(.ed-select-dropdown__item) {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -5253,7 +5238,7 @@ span {
|
|||||||
position: relative;
|
position: relative;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
font-size: 14px;
|
font-size: 14px !important;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
input {
|
input {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { deepCopy } from '@/utils/utils'
|
import { deepCopy } from '@/utils/utils'
|
||||||
import { formatterItem } from '@/views/chart/components/js/formatter'
|
import { formatterItem, isEnLocal } from '@/views/chart/components/js/formatter'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
export const DEFAULT_COLOR_CASE: DeepPartial<ChartAttr> = {
|
export const DEFAULT_COLOR_CASE: DeepPartial<ChartAttr> = {
|
||||||
@ -318,6 +318,32 @@ export const DEFAULT_MISC: ChartMiscAttr = {
|
|||||||
min: 0,
|
min: 0,
|
||||||
max: 0,
|
max: 0,
|
||||||
fieldId: undefined
|
fieldId: undefined
|
||||||
|
},
|
||||||
|
bullet: {
|
||||||
|
bar: {
|
||||||
|
ranges: {
|
||||||
|
fill: ['rgba(0,128,255,0.3)'],
|
||||||
|
size: 20,
|
||||||
|
showType: 'dynamic',
|
||||||
|
fixedRangeNumber: 3,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 4
|
||||||
|
},
|
||||||
|
measures: {
|
||||||
|
fill: ['rgba(0,128,255,1)'],
|
||||||
|
size: 15,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 4
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
fill: 'rgb(0,0,0)',
|
||||||
|
size: 20,
|
||||||
|
showType: 'dynamic',
|
||||||
|
value: 0,
|
||||||
|
symbol: 'line',
|
||||||
|
symbolSize: 4
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,7 +479,8 @@ export const DEFAULT_TABLE_HEADER: ChartTableHeaderAttr = {
|
|||||||
headerGroupConfig: {
|
headerGroupConfig: {
|
||||||
columns: [],
|
columns: [],
|
||||||
meta: []
|
meta: []
|
||||||
}
|
},
|
||||||
|
rowHeaderFreeze: true
|
||||||
}
|
}
|
||||||
export const DEFAULT_TABLE_CELL: ChartTableCellAttr = {
|
export const DEFAULT_TABLE_CELL: ChartTableCellAttr = {
|
||||||
tableFontColor: '#000000',
|
tableFontColor: '#000000',
|
||||||
@ -552,17 +579,6 @@ export const DEFAULT_TITLE_STYLE_DARK = {
|
|||||||
remarkBackgroundColor: '#5A5C62'
|
remarkBackgroundColor: '#5A5C62'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_LEGEND_STYLE: ChartLegendStyle = {
|
|
||||||
show: true,
|
|
||||||
hPosition: 'center',
|
|
||||||
vPosition: 'bottom',
|
|
||||||
orient: 'horizontal',
|
|
||||||
icon: 'circle',
|
|
||||||
color: '#333333',
|
|
||||||
fontSize: 12,
|
|
||||||
size: 4
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = {
|
export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = {
|
||||||
show: true,
|
show: true,
|
||||||
hPosition: 'center',
|
hPosition: 'center',
|
||||||
@ -571,7 +587,24 @@ export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = {
|
|||||||
icon: 'circle',
|
icon: 'circle',
|
||||||
color: '#333333',
|
color: '#333333',
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
size: 4
|
size: 4,
|
||||||
|
showRange: true,
|
||||||
|
sort: 'none',
|
||||||
|
customSort: []
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_LEGEND_STYLE: ChartLegendStyle = {
|
||||||
|
show: true,
|
||||||
|
hPosition: 'center',
|
||||||
|
vPosition: 'bottom',
|
||||||
|
orient: 'horizontal',
|
||||||
|
icon: 'circle',
|
||||||
|
color: '#333333',
|
||||||
|
fontSize: 12,
|
||||||
|
size: 4,
|
||||||
|
showRange: true,
|
||||||
|
sort: 'none',
|
||||||
|
customSort: []
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_LEGEND_STYLE_LIGHT: ChartLegendStyle = {
|
export const DEFAULT_LEGEND_STYLE_LIGHT: ChartLegendStyle = {
|
||||||
@ -634,6 +667,7 @@ export const DEFAULT_XAXIS_STYLE: ChartAxisStyle = {
|
|||||||
},
|
},
|
||||||
axisLabelFormatter: {
|
axisLabelFormatter: {
|
||||||
type: 'auto',
|
type: 'auto',
|
||||||
|
unitLanguage: isEnLocal ? 'en' : 'ch',
|
||||||
unit: 1,
|
unit: 1,
|
||||||
suffix: '',
|
suffix: '',
|
||||||
decimalCount: 2,
|
decimalCount: 2,
|
||||||
@ -680,6 +714,7 @@ export const DEFAULT_YAXIS_STYLE: ChartAxisStyle = {
|
|||||||
},
|
},
|
||||||
axisLabelFormatter: {
|
axisLabelFormatter: {
|
||||||
type: 'auto',
|
type: 'auto',
|
||||||
|
unitLanguage: isEnLocal ? 'en' : 'ch',
|
||||||
unit: 1,
|
unit: 1,
|
||||||
suffix: '',
|
suffix: '',
|
||||||
decimalCount: 2,
|
decimalCount: 2,
|
||||||
@ -724,6 +759,7 @@ export const DEFAULT_YAXIS_EXT_STYLE: ChartAxisStyle = {
|
|||||||
},
|
},
|
||||||
axisLabelFormatter: {
|
axisLabelFormatter: {
|
||||||
type: 'auto',
|
type: 'auto',
|
||||||
|
unitLanguage: isEnLocal ? 'en' : 'ch',
|
||||||
unit: 1,
|
unit: 1,
|
||||||
suffix: '',
|
suffix: '',
|
||||||
decimalCount: 2,
|
decimalCount: 2,
|
||||||
@ -1395,6 +1431,13 @@ export const CHART_TYPE_CONFIGS = [
|
|||||||
value: 'stock-line',
|
value: 'stock-line',
|
||||||
title: t('chart.chart_stock_line'),
|
title: t('chart.chart_stock_line'),
|
||||||
icon: 'stock-line'
|
icon: 'stock-line'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
render: 'antv',
|
||||||
|
category: 'compare',
|
||||||
|
value: 'bullet-graph',
|
||||||
|
title: t('chart.bullet_chart'),
|
||||||
|
icon: 'bullet-graph'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -1651,6 +1694,7 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
|
|||||||
zoomButtonColor: '#aaa',
|
zoomButtonColor: '#aaa',
|
||||||
zoomBackground: '#fff',
|
zoomBackground: '#fff',
|
||||||
tableLayoutMode: 'grid',
|
tableLayoutMode: 'grid',
|
||||||
|
defaultExpandLevel: 1,
|
||||||
calcTopN: false,
|
calcTopN: false,
|
||||||
topN: 5,
|
topN: 5,
|
||||||
topNLabel: t('datasource.other'),
|
topNLabel: t('datasource.other'),
|
||||||
@ -1679,7 +1723,9 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
|
|||||||
radarAreaColor: true,
|
radarAreaColor: true,
|
||||||
circleBorderColor: '#fff',
|
circleBorderColor: '#fff',
|
||||||
circleBorderWidth: 0,
|
circleBorderWidth: 0,
|
||||||
circlePadding: 0
|
circlePadding: 0,
|
||||||
|
quotaPosition: 'col',
|
||||||
|
quotaColLabel: t('dataset.value')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BASE_VIEW_CONFIG = {
|
export const BASE_VIEW_CONFIG = {
|
||||||
|
@ -61,6 +61,7 @@ export const MOBILE_SETTING_DARK = {
|
|||||||
export const DEFAULT_DASHBOARD_STYLE_BASE = {
|
export const DEFAULT_DASHBOARD_STYLE_BASE = {
|
||||||
gap: 'yes',
|
gap: 'yes',
|
||||||
gapSize: 5,
|
gapSize: 5,
|
||||||
|
gapMode: 'middle',
|
||||||
showGrid: false,
|
showGrid: false,
|
||||||
matrixBase: 4, // 当前matrix的基数 (是pcMatrixCount的几倍)
|
matrixBase: 4, // 当前matrix的基数 (是pcMatrixCount的几倍)
|
||||||
resultMode: 'all', // 图表结果显示模式 all 图表 custom 仪表板自定义
|
resultMode: 'all', // 图表结果显示模式 all 图表 custom 仪表板自定义
|
||||||
|
@ -79,7 +79,8 @@ function createExtremumDiv(id, value, formatterCfg, chart) {
|
|||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity 0.2s ease-in-out;
|
transition: opacity 0.2s ease-in-out;
|
||||||
white-space:nowrap;`
|
white-space:nowrap;
|
||||||
|
overflow:auto;`
|
||||||
)
|
)
|
||||||
div.textContent = valueFormatter(value, formatterCfg)
|
div.textContent = valueFormatter(value, formatterCfg)
|
||||||
const span = document.createElement('span')
|
const span = document.createElement('span')
|
||||||
@ -109,7 +110,7 @@ const noChildrenFieldChart = chart => {
|
|||||||
* 支持最值图表的折线图,面积图,柱状图,分组柱状图
|
* 支持最值图表的折线图,面积图,柱状图,分组柱状图
|
||||||
* @param chart
|
* @param chart
|
||||||
*/
|
*/
|
||||||
const supportExtremumChartType = chart => {
|
export const supportExtremumChartType = chart => {
|
||||||
return ['line', 'area', 'bar', 'bar-group'].includes(chart.type)
|
return ['line', 'area', 'bar', 'bar-group'].includes(chart.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +139,8 @@ function removeDivsWithPrefix(parentDivId, prefix) {
|
|||||||
|
|
||||||
export const extremumEvt = (newChart, chart, _options, container) => {
|
export const extremumEvt = (newChart, chart, _options, container) => {
|
||||||
chart.container = container
|
chart.container = container
|
||||||
if (!supportExtremumChartType(chart)) {
|
|
||||||
clearExtremum(chart)
|
clearExtremum(chart)
|
||||||
|
if (!supportExtremumChartType(chart)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { label: labelAttr } = parseJson(chart.customAttr)
|
const { label: labelAttr } = parseJson(chart.customAttr)
|
||||||
@ -150,7 +151,9 @@ export const extremumEvt = (newChart, chart, _options, container) => {
|
|||||||
i.forEach(item => {
|
i.forEach(item => {
|
||||||
delete item._origin.EXTREME
|
delete item._origin.EXTREME
|
||||||
})
|
})
|
||||||
const { minItem, maxItem } = findMinMax(i.filter(item => item._origin.value))
|
const { minItem, maxItem } = findMinMax(
|
||||||
|
i.filter(item => item?._origin?.value !== null && item?._origin?.value !== undefined)
|
||||||
|
)
|
||||||
if (!minItem || !maxItem) {
|
if (!minItem || !maxItem) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -223,6 +226,7 @@ export const createExtremumPoint = (chart, ev) => {
|
|||||||
divParent.style.zIndex = '1'
|
divParent.style.zIndex = '1'
|
||||||
divParent.style.opacity = '0'
|
divParent.style.opacity = '0'
|
||||||
divParent.style.transition = 'opacity 0.2s ease-in-out'
|
divParent.style.transition = 'opacity 0.2s ease-in-out'
|
||||||
|
divParent.style.overflow = 'visible'
|
||||||
// 将父标注加入到图表中
|
// 将父标注加入到图表中
|
||||||
const containerElement = document.getElementById(chart.container)
|
const containerElement = document.getElementById(chart.container)
|
||||||
containerElement.insertBefore(divParent, containerElement.firstChild)
|
containerElement.insertBefore(divParent, containerElement.firstChild)
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { Datum } from '@antv/g2plot'
|
import { find } from 'lodash-es'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { getLocale } from '@/utils/utils'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
export const isEnLocal = !['zh', 'zh-cn', 'zh-CN', 'tw'].includes(getLocale())
|
||||||
|
|
||||||
export const formatterItem = {
|
export const formatterItem = {
|
||||||
type: 'auto', // auto,value,percent
|
type: 'auto', // auto,value,percent
|
||||||
|
unitLanguage: isEnLocal ? 'en' : 'ch',
|
||||||
unit: 1, // 换算单位
|
unit: 1, // 换算单位
|
||||||
suffix: '', // 单位后缀
|
suffix: '', // 单位后缀
|
||||||
decimalCount: 2, // 小数位数
|
decimalCount: 2, // 小数位数
|
||||||
@ -10,12 +16,51 @@ export const formatterItem = {
|
|||||||
|
|
||||||
// 单位list
|
// 单位list
|
||||||
export const unitType = [
|
export const unitType = [
|
||||||
{ name: 'unit_none', value: 1 },
|
{ name: t('chart.unit_none'), value: 1 },
|
||||||
{ name: 'unit_thousand', value: 1000 },
|
{ name: t('chart.unit_thousand'), value: 1000 },
|
||||||
{ name: 'unit_ten_thousand', value: 10000 },
|
{ name: t('chart.unit_ten_thousand'), value: 10000 },
|
||||||
{ name: 'unit_million', value: 1000000 },
|
{ name: t('chart.unit_million'), value: 1000000 },
|
||||||
{ name: 'unit_hundred_million', value: 100000000 }
|
{ name: t('chart.unit_hundred_million'), value: 100000000 }
|
||||||
]
|
]
|
||||||
|
export const unitEnType = [
|
||||||
|
{ name: 'None', value: 1 },
|
||||||
|
{ name: 'Thousand (K)', value: 1000 },
|
||||||
|
{ name: 'Million (M)', value: 1000000 },
|
||||||
|
{ name: 'Billion (B)', value: 1000000000 }
|
||||||
|
]
|
||||||
|
|
||||||
|
export function getUnitTypeList(lang) {
|
||||||
|
if (isEnLocal) {
|
||||||
|
return unitEnType
|
||||||
|
}
|
||||||
|
if (lang === 'ch') {
|
||||||
|
return unitType
|
||||||
|
}
|
||||||
|
return unitEnType
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUnitTypeValue(lang, value) {
|
||||||
|
const list = getUnitTypeList(lang)
|
||||||
|
const item = find(list, l => l.value === value)
|
||||||
|
if (item) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initFormatCfgUnit(cfg) {
|
||||||
|
if (cfg && cfg.unitLanguage === undefined) {
|
||||||
|
cfg.unitLanguage = 'ch'
|
||||||
|
}
|
||||||
|
if (cfg && isEnLocal) {
|
||||||
|
cfg.unitLanguage = 'en'
|
||||||
|
}
|
||||||
|
onChangeFormatCfgUnitLanguage(cfg, cfg.unitLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onChangeFormatCfgUnitLanguage(cfg, lang) {
|
||||||
|
cfg.unit = getUnitTypeValue(lang, cfg.unit)
|
||||||
|
}
|
||||||
|
|
||||||
// 格式化方式
|
// 格式化方式
|
||||||
export const formatterType = [
|
export const formatterType = [
|
||||||
@ -47,17 +92,32 @@ export function valueFormatter(value, formatter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function transUnit(value, formatter) {
|
function transUnit(value, formatter) {
|
||||||
|
initFormatCfgUnit(formatter)
|
||||||
return value / formatter.unit
|
return value / formatter.unit
|
||||||
}
|
}
|
||||||
|
|
||||||
function transDecimal(value, formatter) {
|
function transDecimal(value, formatter) {
|
||||||
const resultV = value.toFixed(formatter.decimalCount)
|
const resultV = retain(value, formatter.decimalCount) as string
|
||||||
if (Object.is(parseFloat(resultV), -0)) {
|
if (Object.is(parseFloat(resultV), -0)) {
|
||||||
return resultV.slice(1)
|
return resultV.slice(1)
|
||||||
}
|
}
|
||||||
return resultV
|
return resultV
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function retain(value, n) {
|
||||||
|
if (!n) return Math.round(value)
|
||||||
|
const tran = Math.round(value * Math.pow(10, n)) / Math.pow(10, n)
|
||||||
|
let tranV = tran.toString()
|
||||||
|
const newVal = tranV.indexOf('.')
|
||||||
|
if (newVal < 0) {
|
||||||
|
tranV += '.'
|
||||||
|
}
|
||||||
|
for (let i = tranV.length - tranV.indexOf('.'); i <= n; i++) {
|
||||||
|
tranV += '0'
|
||||||
|
}
|
||||||
|
return tranV
|
||||||
|
}
|
||||||
|
|
||||||
function transSeparatorAndSuffix(value, formatter) {
|
function transSeparatorAndSuffix(value, formatter) {
|
||||||
let str = value + ''
|
let str = value + ''
|
||||||
if (str.match(/^(\d)(\.\d)?e-(\d)/)) {
|
if (str.match(/^(\d)(\.\d)?e-(\d)/)) {
|
||||||
@ -74,34 +134,27 @@ function transSeparatorAndSuffix(value, formatter) {
|
|||||||
//百分比没有后缀,直接返回
|
//百分比没有后缀,直接返回
|
||||||
return str
|
return str
|
||||||
} else {
|
} else {
|
||||||
if (formatter.unit === 1000) {
|
const unit = formatter.unit
|
||||||
str += '千'
|
|
||||||
} else if (formatter.unit === 10000) {
|
if (formatter.unitLanguage === 'ch') {
|
||||||
str += '万'
|
if (unit === 1000) {
|
||||||
} else if (formatter.unit === 1000000) {
|
str += t('chart.unit_thousand')
|
||||||
str += '百万'
|
} else if (unit === 10000) {
|
||||||
} else if (formatter.unit === 100000000) {
|
str += t('chart.unit_ten_thousand')
|
||||||
str += '亿'
|
} else if (unit === 1000000) {
|
||||||
|
str += t('chart.unit_million')
|
||||||
|
} else if (unit === 100000000) {
|
||||||
|
str += t('chart.unit_hundred_million')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (unit === 1000) {
|
||||||
|
str += 'K'
|
||||||
|
} else if (unit === 1000000) {
|
||||||
|
str += 'M'
|
||||||
|
} else if (unit === 1000000000) {
|
||||||
|
str += 'B'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str + formatter.suffix.replace(/(^\s*)|(\s*$)/g, '')
|
return str + formatter.suffix.replace(/(^\s*)|(\s*$)/g, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function singleDimensionTooltipFormatter(param: Datum, chart: Chart, prop = 'category') {
|
|
||||||
let res
|
|
||||||
const yAxis = chart.yAxis
|
|
||||||
const obj = { name: param[prop], value: param.value }
|
|
||||||
for (let i = 0; i < yAxis.length; i++) {
|
|
||||||
const f = yAxis[i]
|
|
||||||
if (f.name === param[prop]) {
|
|
||||||
if (f.formatterCfg) {
|
|
||||||
res = valueFormatter(param.value, f.formatterCfg)
|
|
||||||
} else {
|
|
||||||
res = valueFormatter(param.value, formatterItem)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
obj.value = res ?? ''
|
|
||||||
return obj
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,656 @@
|
|||||||
|
import { DualAxes, Plot } from '@antv/g2plot'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 Map 来存储实例,键为 chart.container 对象
|
||||||
|
*/
|
||||||
|
export const CAROUSEL_MANAGER_INSTANCES = new Map<string, ChartCarouselTooltip>()
|
||||||
|
/**
|
||||||
|
* 支持的图表类型
|
||||||
|
*/
|
||||||
|
const CHART_CATEGORY = {
|
||||||
|
COLUMN: ['bar', 'bar-stack', 'bar-group', 'bar-group-stack', 'percentage-bar-stack'],
|
||||||
|
LINE: ['line', 'area', 'area-stack'],
|
||||||
|
MIX: ['chart-mix', 'chart-mix-group', 'chart-mix-stack', 'chart-mix-dual-line'],
|
||||||
|
PIE: ['pie', 'pie-donut']
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为柱状图
|
||||||
|
* @param chartType
|
||||||
|
*/
|
||||||
|
export function isColumn(chartType: string) {
|
||||||
|
return CHART_CATEGORY.COLUMN.includes(chartType)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为折线图
|
||||||
|
* @param chartType
|
||||||
|
*/
|
||||||
|
export function isLine(chartType: string) {
|
||||||
|
return CHART_CATEGORY.LINE.includes(chartType)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为饼图
|
||||||
|
* @param chartType
|
||||||
|
*/
|
||||||
|
export function isPie(chartType: string) {
|
||||||
|
return CHART_CATEGORY.PIE.includes(chartType)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否为组合图
|
||||||
|
* @param chartType
|
||||||
|
*/
|
||||||
|
export function isMix(chartType: string) {
|
||||||
|
return CHART_CATEGORY.MIX.includes(chartType)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSupport(chartType: string) {
|
||||||
|
return Object.values(CHART_CATEGORY).some(category => category.includes(chartType))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 轮播配置默认值
|
||||||
|
const DEFAULT_CAROUSEL_CONFIG: Required<CarouselConfig> = {
|
||||||
|
xField: '',
|
||||||
|
duration: 2000,
|
||||||
|
interval: 2000,
|
||||||
|
loop: true
|
||||||
|
}
|
||||||
|
|
||||||
|
type CarouselConfig = {
|
||||||
|
xField: string
|
||||||
|
duration?: number
|
||||||
|
interval?: number
|
||||||
|
loop?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图表轮播提示管理类
|
||||||
|
* */
|
||||||
|
class ChartCarouselTooltip {
|
||||||
|
private plot: Plot | DualAxes
|
||||||
|
private config: Required<CarouselConfig>
|
||||||
|
private currentIndex = 0
|
||||||
|
private values: string[] = []
|
||||||
|
// 合并定时器管理
|
||||||
|
private timers = { interval: null, carousel: null }
|
||||||
|
private states = { paused: false, destroyed: false }
|
||||||
|
// 图表可视性变化
|
||||||
|
private observers: Map<string, IntersectionObserver> = new Map()
|
||||||
|
// 图表元素大小变化
|
||||||
|
private resizeObservers: Map<string, ResizeObserver> = new Map()
|
||||||
|
// 图表是否在可视范围内
|
||||||
|
private chartIsVisible: boolean
|
||||||
|
|
||||||
|
private constructor(plot: Plot | DualAxes, private chart: Chart, config: CarouselConfig) {
|
||||||
|
this.plot = plot
|
||||||
|
this.config = { ...DEFAULT_CAROUSEL_CONFIG, ...config }
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或更新实例
|
||||||
|
* */
|
||||||
|
static manage(plot: Plot | DualAxes, chart: Chart, config: CarouselConfig) {
|
||||||
|
if (!isSupport(chart.type)) return null
|
||||||
|
const container = chart.container
|
||||||
|
let instance = CAROUSEL_MANAGER_INSTANCES.get(container)
|
||||||
|
|
||||||
|
CAROUSEL_MANAGER_INSTANCES.forEach(instance => {
|
||||||
|
if (container.includes('viewDialog')) {
|
||||||
|
instance.paused()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (instance) {
|
||||||
|
instance.update(plot, chart, config)
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
if (isSupport(chart.type)) {
|
||||||
|
instance = new this(plot, chart, config)
|
||||||
|
CAROUSEL_MANAGER_INSTANCES.set(container, instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁实例
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
static destroyByContainer(container: string) {
|
||||||
|
const instance = CAROUSEL_MANAGER_INSTANCES.get(container)
|
||||||
|
if (instance) {
|
||||||
|
instance.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过容器DOM获取对应实例
|
||||||
|
* */
|
||||||
|
static getInstanceByContainer(container: string) {
|
||||||
|
const instance = CAROUSEL_MANAGER_INSTANCES.get(container)
|
||||||
|
if (instance) {
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过chart.id销毁对应实例
|
||||||
|
* 关闭放大图表弹窗,销毁对应实例
|
||||||
|
* 重启图表自身轮播
|
||||||
|
* */
|
||||||
|
static closeEnlargeDialogDestroy(id?: string) {
|
||||||
|
// 首先,暂停并删除包含 'viewDialog' 的实例
|
||||||
|
CAROUSEL_MANAGER_INSTANCES?.forEach((instance, key) => {
|
||||||
|
if (instance.chart.id === id && instance.chart.container.includes('viewDialog')) {
|
||||||
|
const dialogInstance = CAROUSEL_MANAGER_INSTANCES.get(key)
|
||||||
|
if (dialogInstance) {
|
||||||
|
dialogInstance.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setTimeout(() => {
|
||||||
|
// 然后,恢复
|
||||||
|
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
|
||||||
|
if (instance.chartIsVisible) {
|
||||||
|
instance.resume()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停轮播
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
static paused(id?: string) {
|
||||||
|
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
|
||||||
|
if (id && instance.chart.id === id) {
|
||||||
|
setTimeout(() => instance.paused(), 200)
|
||||||
|
}
|
||||||
|
if (!id) {
|
||||||
|
setTimeout(() => instance.paused(), 200)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
static resume(id?: string) {
|
||||||
|
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
|
||||||
|
if (instance.chart.id === id) {
|
||||||
|
instance.paused()
|
||||||
|
setTimeout(() => instance.resume(), 500)
|
||||||
|
}
|
||||||
|
if (!id) {
|
||||||
|
setTimeout(() => instance.resume(), 200)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化核心逻辑
|
||||||
|
* */
|
||||||
|
private init() {
|
||||||
|
this.values = [].concat(this.getUniqueValues())
|
||||||
|
if (!this.values.length) return
|
||||||
|
this.chartIsVisible = true
|
||||||
|
this.states.paused = false
|
||||||
|
this.states.destroyed = false
|
||||||
|
this.bindEventListeners()
|
||||||
|
this.startCarousel()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取图表唯一值集合
|
||||||
|
* */
|
||||||
|
private getUniqueValues() {
|
||||||
|
const data =
|
||||||
|
this.plot instanceof DualAxes
|
||||||
|
? [...this.plot.options.data[0], ...this.plot.options.data[1]]
|
||||||
|
: this.plot.options.data
|
||||||
|
|
||||||
|
return [...new Set(data.map(item => item[this.config.xField]))]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动轮播
|
||||||
|
* */
|
||||||
|
private startCarousel() {
|
||||||
|
if (!this.shouldStart()) {
|
||||||
|
this.stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 定义启动嵌套定时器的函数
|
||||||
|
const startNestedTimers = () => {
|
||||||
|
// 重置当前索引
|
||||||
|
this.currentIndex = 0
|
||||||
|
// 定义递归处理数据数组的函数
|
||||||
|
const processArray = () => {
|
||||||
|
if (this.states.paused || this.states.destroyed || !this.isElementFullyVisible()) return
|
||||||
|
// 获取当前需要显示的值
|
||||||
|
const currentValue = this.values[this.currentIndex]
|
||||||
|
// 计算 Tooltip 显示的位置
|
||||||
|
const point = this.calculatePosition(currentValue)
|
||||||
|
// 高亮当前数据点
|
||||||
|
this.highlightElement(currentValue)
|
||||||
|
if (point) {
|
||||||
|
// 显示 Tooltip,并设置其位置为顶部
|
||||||
|
this.plot.chart.showTooltip(point)
|
||||||
|
this.plot.chart.getController('tooltip').update()
|
||||||
|
}
|
||||||
|
// 更新索引,指向下一个数据点
|
||||||
|
this.currentIndex++
|
||||||
|
if (this.currentIndex > this.values.length) {
|
||||||
|
this.currentIndex = 0
|
||||||
|
this.hideTooltip()
|
||||||
|
this.plot.chart.showTooltip({ x: 0, y: 0 })
|
||||||
|
this.plot.chart.getController('tooltip').update()
|
||||||
|
this.unHighlightPoint(currentValue)
|
||||||
|
this.timers.interval = setTimeout(() => processArray(), this.config.interval)
|
||||||
|
} else {
|
||||||
|
// 如果未遍历完,继续处理下一个数据点
|
||||||
|
this.timers.carousel = setTimeout(() => processArray(), this.config.duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processArray()
|
||||||
|
}
|
||||||
|
this.stop()
|
||||||
|
startNestedTimers()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否满足启动条件' */
|
||||||
|
private shouldStart() {
|
||||||
|
return (
|
||||||
|
this.chart.customAttr?.tooltip?.show &&
|
||||||
|
this.chart.customAttr?.tooltip?.carousel?.enable &&
|
||||||
|
this.values.length > 0 &&
|
||||||
|
this.chartIsVisible
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断图表是否在可视范围内
|
||||||
|
* */
|
||||||
|
private isElementFullyVisible(): boolean {
|
||||||
|
// 全屏
|
||||||
|
const isFullscreen = document.fullscreenElement !== null
|
||||||
|
// 新页面或公共连接
|
||||||
|
const isNewPagePublicLink = document
|
||||||
|
.getElementById('enlarge-inner-content-' + this.chart.id)
|
||||||
|
?.getBoundingClientRect()
|
||||||
|
const isMobileEdit = document.getElementsByClassName('panel-mobile')?.length > 0
|
||||||
|
const isMobileList = document.getElementsByClassName('mobile-com-list')?.length > 0
|
||||||
|
if (isMobileList) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const rect = this.plot.chart.ele.getBoundingClientRect()
|
||||||
|
return (
|
||||||
|
rect.top >= (isFullscreen || isNewPagePublicLink || isMobileEdit ? 0 : 64) &&
|
||||||
|
rect.left >= 0 &&
|
||||||
|
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
||||||
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 计算元素位置(核心定位逻辑)
|
||||||
|
* */
|
||||||
|
private calculatePosition(value: string) {
|
||||||
|
const view = this.plot.chart.views?.[0] || this.plot.chart
|
||||||
|
// 饼图特殊处理
|
||||||
|
if (CHART_CATEGORY.PIE.includes(this.chart.type)) {
|
||||||
|
return this.getPieTooltipPosition(view, value)
|
||||||
|
}
|
||||||
|
if (this.plot instanceof DualAxes) {
|
||||||
|
return this.getDualAxesTooltipPosition(view, value)
|
||||||
|
}
|
||||||
|
const types = view
|
||||||
|
.scale()
|
||||||
|
.getGeometries()
|
||||||
|
.map(item => item.type)
|
||||||
|
let point = { x: 0, y: 0 }
|
||||||
|
if (!types.length) return point
|
||||||
|
types.forEach(type => {
|
||||||
|
if (type === 'interval' || type === 'point') {
|
||||||
|
point = view
|
||||||
|
.scale()
|
||||||
|
.getGeometries()
|
||||||
|
.find(item => item.type === type)
|
||||||
|
.elements.find(item => item.data.field === value && (item.model.x || item.model.y))?.model
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 处理柱状图和折线图,柱状图固定y轴位置
|
||||||
|
const y = CHART_CATEGORY.COLUMN.includes(this.chart.type) ? 0 : [].concat(point?.y)?.[0]
|
||||||
|
return { x: [].concat(point?.x)?.[0], y: y }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算饼图元素位置
|
||||||
|
* */
|
||||||
|
private getPieTooltipPosition(view, value: string) {
|
||||||
|
const piePoint = view
|
||||||
|
.scale()
|
||||||
|
.getGeometries()[0]
|
||||||
|
?.elements.find(item => item.data.field === value)
|
||||||
|
?.getModel()
|
||||||
|
if (!piePoint) {
|
||||||
|
return { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
const coordinates = [
|
||||||
|
{ x: [].concat(piePoint.x)[0], y: piePoint.y[0] },
|
||||||
|
{ x: piePoint.x[0], y: piePoint.y[1] },
|
||||||
|
{ x: piePoint.x[1], y: piePoint.y[0] },
|
||||||
|
{ x: piePoint.x[1], y: piePoint.y[1] }
|
||||||
|
]
|
||||||
|
const index = coordinates.findIndex(coord => {
|
||||||
|
const items = this.plot.chart.getTooltipItems(coord)
|
||||||
|
return items.some(item => item.data.field === value)
|
||||||
|
})
|
||||||
|
if (index !== -1) {
|
||||||
|
return coordinates[index]
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
x: piePoint.x[0],
|
||||||
|
y: piePoint.y[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取双轴图表的 Tooltip 位置
|
||||||
|
* @param view
|
||||||
|
* @param value
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private getDualAxesTooltipPosition(view, value: string) {
|
||||||
|
const xScale = view.getXScale()
|
||||||
|
if (!xScale) return { x: 0, y: 0 }
|
||||||
|
const values = xScale.values
|
||||||
|
if (values.length < 2) {
|
||||||
|
const point = view
|
||||||
|
.getGeometries()?.[0]
|
||||||
|
.elements[view.getGeometries()?.[0].elements?.length - 1].getModel()
|
||||||
|
return point || { x: 0, y: 0 }
|
||||||
|
}
|
||||||
|
const [rangeStart, rangeEnd] = xScale.range
|
||||||
|
const totalMonths = values.length
|
||||||
|
const bandWidth = (rangeEnd - rangeStart) / totalMonths
|
||||||
|
const index = values.indexOf(value)
|
||||||
|
const xPos = rangeStart + bandWidth * (index + 0.5)
|
||||||
|
return view.getCoordinate().convert({ x: xPos, y: 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高亮指定元素
|
||||||
|
* */
|
||||||
|
private highlightElement(value: string) {
|
||||||
|
if (CHART_CATEGORY.LINE.includes(this.chart.type)) return
|
||||||
|
this.unHighlightPoint(value)
|
||||||
|
this.plot.setState(
|
||||||
|
this.getHighlightType(),
|
||||||
|
(data: any) => data[this.config.xField] === value,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消高亮
|
||||||
|
* **/
|
||||||
|
private unHighlightPoint(value?: string) {
|
||||||
|
if (CHART_CATEGORY.LINE.includes(this.chart.type)) return
|
||||||
|
this.plot.setState(
|
||||||
|
this.getHighlightType(),
|
||||||
|
(data: any) => data[this.config.xField] !== value,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
private getHighlightType() {
|
||||||
|
return 'active'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隐藏工具提示
|
||||||
|
* */
|
||||||
|
private hideTooltip() {
|
||||||
|
const container = this.getTooltipContainer()
|
||||||
|
if (container) {
|
||||||
|
container.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取工具提示容器
|
||||||
|
* */
|
||||||
|
private getTooltipContainer() {
|
||||||
|
const tooltipCtl = this.plot.chart.getController('tooltip')
|
||||||
|
if (!tooltipCtl) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return tooltipCtl.tooltip?.cfg?.container
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定事件监听
|
||||||
|
* */
|
||||||
|
private bindEventListeners() {
|
||||||
|
// 定义图表元素ID前缀数组
|
||||||
|
// 图表在不同的显示页面可能有不同的ID前缀
|
||||||
|
const chartElementIds = ['enlarge-inner-content-', 'enlarge-inner-shape-']
|
||||||
|
let chartElement = null
|
||||||
|
|
||||||
|
// 查找图表元素
|
||||||
|
for (const idPrefix of chartElementIds) {
|
||||||
|
chartElement = document.getElementById(idPrefix + this.chart.id)
|
||||||
|
if (chartElement) break
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绑定鼠标进入和离开事件
|
||||||
|
chartElement?.addEventListener('mouseenter', () => this.paused())
|
||||||
|
chartElement?.addEventListener('mouseleave', ev => {
|
||||||
|
setTimeout(() => {
|
||||||
|
// 获取鼠标位置
|
||||||
|
const mouseX = ev.clientX
|
||||||
|
const mouseY = ev.clientY
|
||||||
|
// 获取div的边界信息
|
||||||
|
const rect = chartElement.getBoundingClientRect()
|
||||||
|
// 判断鼠标位置是否在div内
|
||||||
|
const isInside =
|
||||||
|
mouseX >= rect.left + 10 &&
|
||||||
|
mouseX <= rect.right - 10 &&
|
||||||
|
mouseY >= rect.top + 10 &&
|
||||||
|
mouseY <= rect.bottom - 10
|
||||||
|
console.log(isInside)
|
||||||
|
if (!isInside) {
|
||||||
|
this.paused()
|
||||||
|
this.resume()
|
||||||
|
}
|
||||||
|
}, 300)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定义鼠标滚轮事件处理函数
|
||||||
|
const handleMouseWheel = this.debounce(() => {
|
||||||
|
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
|
||||||
|
instance.paused()
|
||||||
|
instance.resume()
|
||||||
|
})
|
||||||
|
}, 50)
|
||||||
|
// 定义 touchmove 事件处理函数(移动端)
|
||||||
|
const handleTouchMove = (event: TouchEvent) => {
|
||||||
|
handleMouseWheel(event)
|
||||||
|
}
|
||||||
|
// 获取目标元素,优先全屏预览
|
||||||
|
const targetDiv =
|
||||||
|
document.getElementById('de-preview-content') ||
|
||||||
|
document.getElementById('preview-canvas-main') ||
|
||||||
|
document.getElementById('dv-main-center') ||
|
||||||
|
document.getElementById('edit-canvas-main') ||
|
||||||
|
document.getElementById('canvas-mark-line') ||
|
||||||
|
document.getElementById('de-canvas-canvas-main')
|
||||||
|
// 绑定目标元素的事件
|
||||||
|
if (targetDiv) {
|
||||||
|
targetDiv.removeEventListener('wheel', handleMouseWheel)
|
||||||
|
targetDiv.addEventListener('wheel', handleMouseWheel)
|
||||||
|
//移除和添加 touchmove 事件监听器(移动端)
|
||||||
|
targetDiv.removeEventListener('touchmove', handleTouchMove)
|
||||||
|
targetDiv.addEventListener('touchmove', handleTouchMove)
|
||||||
|
}
|
||||||
|
// 页面可见性控制
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (document.visibilityState === 'hidden') {
|
||||||
|
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
|
||||||
|
instance.paused()
|
||||||
|
})
|
||||||
|
} else if (this.chartIsVisible) {
|
||||||
|
CAROUSEL_MANAGER_INSTANCES?.forEach(instance => {
|
||||||
|
instance.resume()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 元素可视性观察(交叉观察器)
|
||||||
|
this.setupIntersectionObserver()
|
||||||
|
// 元素大小观察(大小观察器)
|
||||||
|
this.setupResizeObserver()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置暂停状态
|
||||||
|
* */
|
||||||
|
private setPaused(state: boolean) {
|
||||||
|
this.states.paused = state
|
||||||
|
state ? this.stop() : this.startCarousel()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置交叉观察器
|
||||||
|
* */
|
||||||
|
private setupIntersectionObserver() {
|
||||||
|
setTimeout(() => {
|
||||||
|
// 监听元素可见性变化,全部可见时开始轮播
|
||||||
|
if (!this.observers.get(this.plot.chart.ele.id)) {
|
||||||
|
this.observers.set(
|
||||||
|
this.plot.chart.ele.id,
|
||||||
|
new IntersectionObserver(
|
||||||
|
entries => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.intersectionRatio < 0.7) {
|
||||||
|
this.paused()
|
||||||
|
this.chartIsVisible = false
|
||||||
|
} else {
|
||||||
|
this.paused()
|
||||||
|
this.chartIsVisible = true
|
||||||
|
this.resume()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ threshold: [0.7] }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
this.observers.get(this.plot.chart.ele.id).observe(this.plot.chart.ele)
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置元素大小观察器
|
||||||
|
* 当元素全部可见时
|
||||||
|
* 图表的最外层元素
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private setupResizeObserver() {
|
||||||
|
// 放大图表弹窗不需要监听
|
||||||
|
if (this.plot.chart.ele.id.includes('viewDialog')) return
|
||||||
|
// 创建防抖回调函数
|
||||||
|
const debouncedCallback = (entries: ResizeObserverEntry[]) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.target) {
|
||||||
|
this.debounce(() => {
|
||||||
|
this.paused()
|
||||||
|
this.resume()
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 监听元素大小, 发生变化时重新轮播
|
||||||
|
if (!this.resizeObservers.get(this.plot.chart.ele.id)) {
|
||||||
|
this.resizeObservers.set(this.plot.chart.ele.id, new ResizeObserver(debouncedCallback))
|
||||||
|
this.resizeObservers.get(this.plot.chart.ele.id).observe(this.plot.chart.ele)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新配置
|
||||||
|
* */
|
||||||
|
private update(plot: Plot | DualAxes, chart: Chart, config: CarouselConfig) {
|
||||||
|
this.stop()
|
||||||
|
this.plot = plot
|
||||||
|
this.chart = chart
|
||||||
|
this.config = { ...this.config, ...config }
|
||||||
|
this.currentIndex = 0
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止定时器
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private stop() {
|
||||||
|
clearTimeout(this.timers.interval)
|
||||||
|
clearTimeout(this.timers.carousel)
|
||||||
|
this.timers = { interval: null, carousel: null }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁实例
|
||||||
|
* */
|
||||||
|
destroy() {
|
||||||
|
this.stop()
|
||||||
|
this.clearObserver()
|
||||||
|
this.states.destroyed = true
|
||||||
|
CAROUSEL_MANAGER_INSTANCES.delete(this.chart.container)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 清除观察器
|
||||||
|
* */
|
||||||
|
clearObserver() {
|
||||||
|
const observer = this.observers.get(this.plot.chart.ele.id)
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect()
|
||||||
|
this.observers.delete(this.plot.chart.ele.id)
|
||||||
|
}
|
||||||
|
const resizeObservers = this.resizeObservers.get(this.plot.chart.ele.id)
|
||||||
|
if (resizeObservers) {
|
||||||
|
resizeObservers.disconnect()
|
||||||
|
this.resizeObservers.delete(this.plot.chart.ele.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** 暂停 */
|
||||||
|
paused() {
|
||||||
|
this.hideTooltip()
|
||||||
|
this.unHighlightPoint()
|
||||||
|
this.setPaused(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 恢复 */
|
||||||
|
resume() {
|
||||||
|
this.setPaused(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 防抖
|
||||||
|
*/
|
||||||
|
private debounce(func: (...args: any[]) => void, delay: number): (...args: any[]) => void {
|
||||||
|
let timeout: number | null = null
|
||||||
|
return (...args: any[]) => {
|
||||||
|
if (timeout) clearTimeout(timeout)
|
||||||
|
timeout = window.setTimeout(() => {
|
||||||
|
func(...args)
|
||||||
|
}, delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChartCarouselTooltip
|
@ -7,7 +7,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
flow,
|
flow,
|
||||||
hexColorToRGBA,
|
hexColorToRGBA,
|
||||||
hexToRgba,
|
|
||||||
parseJson,
|
parseJson,
|
||||||
setUpGroupSeriesColor,
|
setUpGroupSeriesColor,
|
||||||
setUpStackSeriesColor
|
setUpStackSeriesColor
|
||||||
@ -21,6 +20,7 @@ import {
|
|||||||
} from '@/views/chart/components/js/panel/charts/bar/common'
|
} from '@/views/chart/components/js/panel/charts/bar/common'
|
||||||
import {
|
import {
|
||||||
configPlotTooltipEvent,
|
configPlotTooltipEvent,
|
||||||
|
configRoundAngle,
|
||||||
getLabel,
|
getLabel,
|
||||||
getPadding,
|
getPadding,
|
||||||
getTooltipContainer,
|
getTooltipContainer,
|
||||||
@ -43,7 +43,14 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
|
|||||||
...BAR_EDITOR_PROPERTY_INNER,
|
...BAR_EDITOR_PROPERTY_INNER,
|
||||||
'basic-style-selector': [...BAR_EDITOR_PROPERTY_INNER['basic-style-selector'], 'seriesColor'],
|
'basic-style-selector': [...BAR_EDITOR_PROPERTY_INNER['basic-style-selector'], 'seriesColor'],
|
||||||
'label-selector': ['vPosition', 'seriesLabelFormatter', 'showExtremum'],
|
'label-selector': ['vPosition', 'seriesLabelFormatter', 'showExtremum'],
|
||||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
'tooltip-selector': [
|
||||||
|
'fontSize',
|
||||||
|
'color',
|
||||||
|
'backgroundColor',
|
||||||
|
'seriesTooltipFormatter',
|
||||||
|
'show',
|
||||||
|
'carousel'
|
||||||
|
],
|
||||||
'y-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['y-axis-selector'], 'axisLabelFormatter']
|
'y-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['y-axis-selector'], 'axisLabelFormatter']
|
||||||
}
|
}
|
||||||
protected baseOptions: ColumnOptions = {
|
protected baseOptions: ColumnOptions = {
|
||||||
@ -69,11 +76,14 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
|
|||||||
|
|
||||||
async drawChart(drawOptions: G2PlotDrawOptions<Column>): Promise<Column> {
|
async drawChart(drawOptions: G2PlotDrawOptions<Column>): Promise<Column> {
|
||||||
const { chart, container, action } = drawOptions
|
const { chart, container, action } = drawOptions
|
||||||
if (!chart?.data?.data?.length) {
|
|
||||||
chart.container = container
|
chart.container = container
|
||||||
|
if (!chart?.data?.data?.length) {
|
||||||
clearExtremum(chart)
|
clearExtremum(chart)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const isGroup = 'bar-group' === this.name && chart.xAxisExt?.length > 0
|
||||||
|
const isStack =
|
||||||
|
['bar-stack', 'bar-group-stack'].includes(this.name) && chart.extStack?.length > 0
|
||||||
const data = cloneDeep(drawOptions.chart.data?.data)
|
const data = cloneDeep(drawOptions.chart.data?.data)
|
||||||
const initOptions: ColumnOptions = {
|
const initOptions: ColumnOptions = {
|
||||||
...this.baseOptions,
|
...this.baseOptions,
|
||||||
@ -108,7 +118,7 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
|
|||||||
const label = {
|
const label = {
|
||||||
fields: [],
|
fields: [],
|
||||||
...tmpOptions.label,
|
...tmpOptions.label,
|
||||||
formatter: (data: Datum, _point) => {
|
formatter: (data: Datum) => {
|
||||||
if (data.EXTREME) {
|
if (data.EXTREME) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@ -174,19 +184,9 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
|
|||||||
color
|
color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (basicStyle.radiusColumnBar === 'roundAngle') {
|
|
||||||
const columnStyle = {
|
|
||||||
radius: [
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius
|
|
||||||
]
|
|
||||||
}
|
|
||||||
options = {
|
options = {
|
||||||
...options,
|
...options,
|
||||||
columnStyle
|
...configRoundAngle(chart, 'columnStyle')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let columnWidthRatio
|
let columnWidthRatio
|
||||||
const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio
|
const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio
|
||||||
@ -227,7 +227,10 @@ export class Bar extends G2PlotChartView<ColumnOptions, Column> {
|
|||||||
tickCount: axisValue.splitCount
|
tickCount: axisValue.splitCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { ...tmpOptions, ...axis }
|
// 根据axis的最小值,过滤options中的data数据,过滤掉小于最小值的数据
|
||||||
|
const { data } = options
|
||||||
|
const newData = data.filter(item => item.value >= axisValue.min)
|
||||||
|
return { ...tmpOptions, data: newData, ...axis }
|
||||||
}
|
}
|
||||||
return tmpOptions
|
return tmpOptions
|
||||||
}
|
}
|
||||||
@ -276,7 +279,14 @@ export class StackBar extends Bar {
|
|||||||
'totalFormatter',
|
'totalFormatter',
|
||||||
'showStackQuota'
|
'showStackQuota'
|
||||||
],
|
],
|
||||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
|
'tooltip-selector': [
|
||||||
|
'fontSize',
|
||||||
|
'color',
|
||||||
|
'backgroundColor',
|
||||||
|
'tooltipFormatter',
|
||||||
|
'show',
|
||||||
|
'carousel'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
||||||
let label = getLabel(chart)
|
let label = getLabel(chart)
|
||||||
@ -438,6 +448,74 @@ export class GroupBar extends StackBar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async drawChart(drawOptions: G2PlotDrawOptions<Column>): Promise<Column> {
|
||||||
|
const plot = await super.drawChart(drawOptions)
|
||||||
|
if (!plot) {
|
||||||
|
return plot
|
||||||
|
}
|
||||||
|
const { chart } = drawOptions
|
||||||
|
const { xAxis, xAxisExt, yAxis } = chart
|
||||||
|
let innerSort = !!(xAxis.length && xAxisExt.length && yAxis.length)
|
||||||
|
if (innerSort && yAxis[0].sort === 'none') {
|
||||||
|
innerSort = false
|
||||||
|
}
|
||||||
|
if (innerSort && xAxisExt[0].sort !== 'none') {
|
||||||
|
const sortPriority = chart.sortPriority ?? []
|
||||||
|
const yAxisIndex = sortPriority?.findIndex(e => e.id === yAxis[0].id)
|
||||||
|
const xAxisExtIndex = sortPriority?.findIndex(e => e.id === xAxisExt[0].id)
|
||||||
|
if (xAxisExtIndex <= yAxisIndex) {
|
||||||
|
innerSort = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!innerSort) {
|
||||||
|
return plot
|
||||||
|
}
|
||||||
|
plot.chart.once('beforepaint', () => {
|
||||||
|
const geo = plot.chart.geometries[0]
|
||||||
|
const originMapping = geo.beforeMapping.bind(geo)
|
||||||
|
geo.beforeMapping = originData => {
|
||||||
|
const values = geo.getXScale().values
|
||||||
|
const valueMap = values.reduce((p, n) => {
|
||||||
|
if (!p?.[n]) {
|
||||||
|
p[n] = {
|
||||||
|
fieldArr: [],
|
||||||
|
indexArr: [],
|
||||||
|
dataArr: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
originData.forEach((arr, arrIndex) => {
|
||||||
|
arr.forEach((item, index) => {
|
||||||
|
if (item._origin.field === n) {
|
||||||
|
p[n].fieldArr.push(item.field)
|
||||||
|
p[n].indexArr.push([arrIndex, index])
|
||||||
|
p[n].dataArr.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return p
|
||||||
|
}, {})
|
||||||
|
values.forEach(v => {
|
||||||
|
const item = valueMap[v]
|
||||||
|
item.dataArr.sort((a, b) => {
|
||||||
|
if (yAxis[0].sort === 'asc') {
|
||||||
|
return a.value - b.value
|
||||||
|
}
|
||||||
|
if (yAxis[0].sort === 'desc') {
|
||||||
|
return b.value - a.value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
item.indexArr.forEach((index, i) => {
|
||||||
|
item.dataArr[i].field = item.fieldArr[i]
|
||||||
|
originData[index[0]][index[1]] = item.dataArr[i]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return originMapping(originData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return plot
|
||||||
|
}
|
||||||
|
|
||||||
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
||||||
const tmpLabel = getLabel(chart)
|
const tmpLabel = getLabel(chart)
|
||||||
if (!tmpLabel) {
|
if (!tmpLabel) {
|
||||||
@ -448,7 +526,7 @@ export class GroupBar extends StackBar {
|
|||||||
baseOptions.label.style.fill = labelAttr.color
|
baseOptions.label.style.fill = labelAttr.color
|
||||||
const label = {
|
const label = {
|
||||||
...baseOptions.label,
|
...baseOptions.label,
|
||||||
formatter: function (param: Datum, _point) {
|
formatter: function (param: Datum) {
|
||||||
if (param.EXTREME) {
|
if (param.EXTREME) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@ -492,6 +570,7 @@ export class GroupBar extends StackBar {
|
|||||||
super(name)
|
super(name)
|
||||||
this.baseOptions = {
|
this.baseOptions = {
|
||||||
...this.baseOptions,
|
...this.baseOptions,
|
||||||
|
marginRatio: 0,
|
||||||
isGroup: true,
|
isGroup: true,
|
||||||
isStack: false,
|
isStack: false,
|
||||||
meta: {
|
meta: {
|
||||||
@ -606,7 +685,7 @@ export class PercentageStackBar extends GroupStackBar {
|
|||||||
propertyInner = {
|
propertyInner = {
|
||||||
...this['propertyInner'],
|
...this['propertyInner'],
|
||||||
'label-selector': ['color', 'fontSize', 'vPosition', 'reserveDecimalCount'],
|
'label-selector': ['color', 'fontSize', 'vPosition', 'reserveDecimalCount'],
|
||||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show']
|
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show', 'carousel']
|
||||||
}
|
}
|
||||||
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions {
|
||||||
const baseOptions = super.configLabel(chart, options)
|
const baseOptions = super.configLabel(chart, options)
|
||||||
|
@ -6,14 +6,14 @@ import { cloneDeep, defaultTo, isEmpty, map } from 'lodash-es'
|
|||||||
import {
|
import {
|
||||||
configAxisLabelLengthLimit,
|
configAxisLabelLengthLimit,
|
||||||
configPlotTooltipEvent,
|
configPlotTooltipEvent,
|
||||||
|
configRoundAngle,
|
||||||
getPadding,
|
getPadding,
|
||||||
getTooltipContainer,
|
getTooltipContainer,
|
||||||
getTooltipItemConditionColor,
|
getTooltipItemConditionColor,
|
||||||
getYAxis,
|
getYAxis,
|
||||||
getYAxisExt,
|
getYAxisExt,
|
||||||
setGradientColor,
|
setGradientColor,
|
||||||
TOOLTIP_TPL,
|
TOOLTIP_TPL
|
||||||
addConditionsStyleColorToData
|
|
||||||
} from '@/views/chart/components/js/panel/common/common_antv'
|
} from '@/views/chart/components/js/panel/common/common_antv'
|
||||||
import type {
|
import type {
|
||||||
BidirectionalBar as G2BidirectionalBar,
|
BidirectionalBar as G2BidirectionalBar,
|
||||||
@ -213,19 +213,9 @@ export class BidirectionalHorizontalBar extends G2PlotChartView<
|
|||||||
...options,
|
...options,
|
||||||
layout: basicStyle.layout
|
layout: basicStyle.layout
|
||||||
}
|
}
|
||||||
if (basicStyle.radiusColumnBar === 'roundAngle') {
|
|
||||||
const barStyle = {
|
|
||||||
radius: [
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius
|
|
||||||
]
|
|
||||||
}
|
|
||||||
options = {
|
options = {
|
||||||
...options,
|
...options,
|
||||||
barStyle
|
...configRoundAngle(chart, 'barStyle')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,507 @@
|
|||||||
|
import type {
|
||||||
|
Bullet as G2Bullet,
|
||||||
|
BulletOptions as G2BulletOptions
|
||||||
|
} from '@antv/g2plot/esm/plots/bullet'
|
||||||
|
import {
|
||||||
|
G2PlotChartView,
|
||||||
|
G2PlotDrawOptions
|
||||||
|
} from '@/views/chart/components/js/panel/types/impl/g2plot'
|
||||||
|
import {
|
||||||
|
BAR_AXIS_TYPE,
|
||||||
|
BAR_EDITOR_PROPERTY,
|
||||||
|
BAR_EDITOR_PROPERTY_INNER
|
||||||
|
} from '@/views/chart/components/js/panel/charts/bar/common'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import { flow, parseJson } from '@/views/chart/components/js/util'
|
||||||
|
import { BulletOptions } from '@antv/g2plot'
|
||||||
|
import { isEmpty } from 'lodash-es'
|
||||||
|
import {
|
||||||
|
configAxisLabelLengthLimit,
|
||||||
|
configPlotTooltipEvent,
|
||||||
|
getPadding,
|
||||||
|
getTooltipContainer,
|
||||||
|
TOOLTIP_TPL
|
||||||
|
} from '@/views/chart/components/js/panel/common/common_antv'
|
||||||
|
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子弹图
|
||||||
|
*/
|
||||||
|
export class BulletGraph extends G2PlotChartView<G2BulletOptions, G2Bullet> {
|
||||||
|
constructor() {
|
||||||
|
super('bullet-graph', [])
|
||||||
|
}
|
||||||
|
|
||||||
|
axis: AxisType[] = [...BAR_AXIS_TYPE, 'yAxisExt', 'extBubble']
|
||||||
|
axisConfig = {
|
||||||
|
...this['axisConfig'],
|
||||||
|
xAxis: { name: `${t('chart.form_type')} / ${t('chart.dimension')}`, type: 'd', limit: 1 },
|
||||||
|
yAxis: { name: `${t('chart.progress_current')} / ${t('chart.quota')}`, type: 'q', limit: 1 },
|
||||||
|
yAxisExt: { name: `${t('chart.progress_target')} / ${t('chart.quota')}`, type: 'q', limit: 1 },
|
||||||
|
extBubble: {
|
||||||
|
name: `${t('chart.range_bg')} / ${t('chart.quota')}`,
|
||||||
|
type: 'q',
|
||||||
|
allowEmpty: true,
|
||||||
|
limit: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties: EditorProperty[] = [
|
||||||
|
...BAR_EDITOR_PROPERTY.filter(
|
||||||
|
item => !['function-cfg', 'assist-line', 'threshold'].includes(item)
|
||||||
|
),
|
||||||
|
'bullet-graph-selector'
|
||||||
|
]
|
||||||
|
propertyInner = {
|
||||||
|
'basic-style-selector': ['radiusColumnBar', 'layout'],
|
||||||
|
'label-selector': ['hPosition', 'fontSize', 'color', 'labelFormatter'],
|
||||||
|
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||||
|
'x-axis-selector': [
|
||||||
|
...BAR_EDITOR_PROPERTY_INNER['x-axis-selector'].filter(item => item != 'position'),
|
||||||
|
'showLengthLimit'
|
||||||
|
],
|
||||||
|
'y-axis-selector': [
|
||||||
|
...BAR_EDITOR_PROPERTY_INNER['y-axis-selector'].filter(
|
||||||
|
item => item !== 'axisValue' && item !== 'position'
|
||||||
|
),
|
||||||
|
'axisLabelFormatter'
|
||||||
|
],
|
||||||
|
'legend-selector': ['showRange', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition']
|
||||||
|
}
|
||||||
|
|
||||||
|
async drawChart(drawOption: G2PlotDrawOptions<G2Bullet>): Promise<G2Bullet> {
|
||||||
|
const { chart, container, action } = drawOption
|
||||||
|
if (!chart.data?.data?.length) return
|
||||||
|
const result = mergeBulletData(chart)
|
||||||
|
// 处理自定义区间
|
||||||
|
const { bullet } = parseJson(chart.customAttr).misc
|
||||||
|
if (bullet.bar.ranges.showType === 'fixed') {
|
||||||
|
const customRange = bullet.bar.ranges.fixedRange?.map(item => item.fixedRangeValue) || [0]
|
||||||
|
result.forEach(item => (item.ranges = customRange))
|
||||||
|
} else {
|
||||||
|
result.forEach(item => (item.ranges = item.originalRanges))
|
||||||
|
}
|
||||||
|
// 处理自定义目标值
|
||||||
|
if (bullet.bar.target.showType === 'fixed') {
|
||||||
|
const customTarget = bullet.bar.target.value || 0
|
||||||
|
result.forEach(item => (item.target = customTarget))
|
||||||
|
} else {
|
||||||
|
result.forEach(item => (item.target = item.originalTarget))
|
||||||
|
}
|
||||||
|
const initialOptions: BulletOptions = {
|
||||||
|
appendPadding: getPadding(chart),
|
||||||
|
data: result.reverse(),
|
||||||
|
measureField: 'measures',
|
||||||
|
rangeField: 'ranges',
|
||||||
|
targetField: 'target',
|
||||||
|
xField: 'title',
|
||||||
|
meta: {
|
||||||
|
title: {
|
||||||
|
type: 'cat'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
interactions: [
|
||||||
|
{
|
||||||
|
type: 'active-region',
|
||||||
|
cfg: {
|
||||||
|
start: [{ trigger: 'element:mousemove', action: 'active-region:show' }],
|
||||||
|
end: [{ trigger: 'element:mouseleave', action: 'active-region:hide' }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
const options = this.setupOptions(chart, initialOptions)
|
||||||
|
let newChart = null
|
||||||
|
const { Bullet: BulletClass } = await import('@antv/g2plot/esm/plots/bullet')
|
||||||
|
newChart = new BulletClass(container, options)
|
||||||
|
newChart.on('element:click', ev => {
|
||||||
|
const pointData = ev?.data?.data
|
||||||
|
const dimensionList = options.data.find(item => item.title === pointData.title)?.dimensionList
|
||||||
|
const actionParams = {
|
||||||
|
x: ev.x,
|
||||||
|
y: ev.y,
|
||||||
|
data: {
|
||||||
|
data: {
|
||||||
|
...pointData,
|
||||||
|
dimensionList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action(actionParams)
|
||||||
|
})
|
||||||
|
configPlotTooltipEvent(chart, newChart)
|
||||||
|
configAxisLabelLengthLimit(chart, newChart, null)
|
||||||
|
return newChart
|
||||||
|
}
|
||||||
|
|
||||||
|
protected configBasicStyle(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
const basicStyle = parseJson(chart.customAttr).basicStyle
|
||||||
|
const { radiusColumnBar, columnBarRightAngleRadius, layout } = basicStyle
|
||||||
|
let radiusValue = 0
|
||||||
|
let rangeLength = 1
|
||||||
|
if (radiusColumnBar === 'roundAngle' || radiusColumnBar === 'topRoundAngle') {
|
||||||
|
radiusValue = columnBarRightAngleRadius
|
||||||
|
rangeLength = options.data[0]?.ranges?.length
|
||||||
|
}
|
||||||
|
const barRadiusStyle = { radius: Array(2).fill(radiusValue) }
|
||||||
|
const baseRadius = [...barRadiusStyle.radius, ...barRadiusStyle.radius]
|
||||||
|
options = {
|
||||||
|
...options,
|
||||||
|
bulletStyle: {
|
||||||
|
range: datum => {
|
||||||
|
if (!datum.rKey) return { fill: 'rgba(0, 0, 0, 0)' }
|
||||||
|
if (rangeLength === 1) {
|
||||||
|
return {
|
||||||
|
radius:
|
||||||
|
radiusColumnBar === 'topRoundAngle' ? [...barRadiusStyle.radius, 0, 0] : baseRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rangeLength > 1 && datum.rKey === 'ranges_0') {
|
||||||
|
return {
|
||||||
|
radius: radiusColumnBar === 'topRoundAngle' ? [] : [0, 0, ...barRadiusStyle.radius]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rangeLength > 1 && datum.rKey === 'ranges_' + (rangeLength - 1)) {
|
||||||
|
return { radius: [...barRadiusStyle.radius, 0, 0] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
measure: datum => {
|
||||||
|
if (datum.measures) {
|
||||||
|
return {
|
||||||
|
radius:
|
||||||
|
radiusColumnBar === 'topRoundAngle' ? [...barRadiusStyle.radius, 0, 0] : baseRadius
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
target: datum => (datum.tKey === 'target' ? { lineWidth: 2 } : undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (layout === 'vertical') options = { ...options, layout: 'vertical' }
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
protected configMisc(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
const { bullet } = parseJson(chart.customAttr).misc
|
||||||
|
const isDynamic = bullet.bar.ranges.showType === 'dynamic'
|
||||||
|
// 动态背景按大小升序
|
||||||
|
const rangeColor = isDynamic
|
||||||
|
? bullet.bar.ranges.fill
|
||||||
|
: bullet.bar.ranges.fixedRange
|
||||||
|
?.sort((a, b) => (a.fixedRangeValue ?? 0) - (b.fixedRangeValue ?? 0))
|
||||||
|
.map(item => item.fill) || []
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
color: {
|
||||||
|
measure: [].concat(bullet.bar.measures.fill),
|
||||||
|
range: [].concat(rangeColor),
|
||||||
|
target: [].concat(bullet.bar.target.fill)
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
measure: bullet.bar.measures.size,
|
||||||
|
range: bullet.bar.ranges.size,
|
||||||
|
target: bullet.bar.target.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected configXAxis(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
const tmpOptions = super.configXAxis(chart, options)
|
||||||
|
if (!tmpOptions.xAxis || !tmpOptions.xAxis.label) return tmpOptions
|
||||||
|
|
||||||
|
const { layout, xAxis } = tmpOptions
|
||||||
|
const position = xAxis.position
|
||||||
|
const style: any = { ...xAxis.label.style }
|
||||||
|
|
||||||
|
if (layout === 'vertical') {
|
||||||
|
style.textAlign = 'center'
|
||||||
|
style.textBaseline = position === 'bottom' ? 'top' : 'bottom'
|
||||||
|
} else {
|
||||||
|
style.textAlign = position === 'bottom' ? 'end' : 'start'
|
||||||
|
style.textBaseline = 'middle'
|
||||||
|
}
|
||||||
|
|
||||||
|
xAxis.label.style = style
|
||||||
|
return tmpOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
protected configYAxis(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
const tmpOptions = super.configYAxis(chart, options)
|
||||||
|
if (!tmpOptions.yAxis || !tmpOptions.yAxis.label) return tmpOptions
|
||||||
|
|
||||||
|
const yAxis = parseJson(chart.customStyle).yAxis
|
||||||
|
tmpOptions.yAxis.label.formatter = value => valueFormatter(value, yAxis.axisLabelFormatter)
|
||||||
|
|
||||||
|
const { layout, yAxis: yAxisConfig } = tmpOptions
|
||||||
|
const position = yAxisConfig.position
|
||||||
|
const style: any = { ...yAxisConfig.label.style }
|
||||||
|
|
||||||
|
if (layout === 'vertical') {
|
||||||
|
style.textAlign = position === 'left' ? 'end' : 'start'
|
||||||
|
style.textBaseline = 'middle'
|
||||||
|
} else {
|
||||||
|
style.textAlign = 'center'
|
||||||
|
style.textBaseline = position === 'left' ? 'top' : 'bottom'
|
||||||
|
}
|
||||||
|
|
||||||
|
yAxisConfig.label.style = style
|
||||||
|
return tmpOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
protected configLabel(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
const tmpOptions = super.configLabel(chart, options)
|
||||||
|
if (!tmpOptions.label) return tmpOptions
|
||||||
|
|
||||||
|
const labelAttr = parseJson(chart.customAttr).label
|
||||||
|
const label: any = {
|
||||||
|
...tmpOptions.label,
|
||||||
|
formatter: param =>
|
||||||
|
param.mKey === 'measures'
|
||||||
|
? valueFormatter(param.measures, labelAttr.labelFormatter)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
return { ...tmpOptions, label: { measure: label } }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected configLegend(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
const baseLegend = super.configLegend(chart, options).legend
|
||||||
|
if (!baseLegend) return options
|
||||||
|
|
||||||
|
const { bullet } = parseJson(chart.customAttr).misc
|
||||||
|
const customStyleLegend = parseJson(chart.customStyle).legend
|
||||||
|
const items = []
|
||||||
|
|
||||||
|
const createLegendItem = (value, name, symbol, fill, size = 4) => ({
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
marker: { symbol, style: { fill, stroke: value === 'measure' ? '' : fill, r: size } }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (customStyleLegend.showRange) {
|
||||||
|
if (bullet.bar.ranges.showType === 'dynamic') {
|
||||||
|
if (chart.extBubble.length) {
|
||||||
|
const rangeName = chart.extBubble[0]?.chartShowName || bullet.bar.ranges.name
|
||||||
|
items.push(
|
||||||
|
createLegendItem(
|
||||||
|
'dynamic',
|
||||||
|
rangeName || chart.extBubble[0]?.name,
|
||||||
|
bullet.bar.ranges.symbol,
|
||||||
|
[].concat(bullet.bar.ranges.fill)[0],
|
||||||
|
bullet.bar.ranges.symbolSize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bullet.bar.ranges.fixedRange?.forEach(item => {
|
||||||
|
items.push(
|
||||||
|
createLegendItem(
|
||||||
|
item.name,
|
||||||
|
item.name,
|
||||||
|
bullet.bar.ranges.symbol,
|
||||||
|
item.fill,
|
||||||
|
bullet.bar.ranges.symbolSize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetName = chart.yAxisExt[0]?.chartShowName || bullet.bar.target.name
|
||||||
|
items.push(
|
||||||
|
createLegendItem(
|
||||||
|
'target',
|
||||||
|
targetName || chart.yAxisExt[0]?.name,
|
||||||
|
'line',
|
||||||
|
[].concat(bullet.bar.target.fill)[0],
|
||||||
|
bullet.bar.ranges.symbolSize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const measureName = chart.yAxis[0]?.chartShowName || bullet.bar.measures.name
|
||||||
|
items.push(
|
||||||
|
createLegendItem(
|
||||||
|
'measure',
|
||||||
|
measureName || chart.yAxis[0]?.name,
|
||||||
|
'square',
|
||||||
|
[].concat(bullet.bar.measures.fill)[0],
|
||||||
|
bullet.bar.ranges.symbolSize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...options,
|
||||||
|
legend: { custom: true, position: baseLegend.position, layout: baseLegend.layout, items }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected configTooltip(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
const customAttr: DeepPartial<ChartAttr> = parseJson(chart.customAttr)
|
||||||
|
const tooltipAttr = customAttr.tooltip
|
||||||
|
const { bullet } = parseJson(chart.customAttr).misc
|
||||||
|
if (!tooltipAttr.show) return { ...options, tooltip: false }
|
||||||
|
|
||||||
|
const formatterMap = tooltipAttr.seriesTooltipFormatter
|
||||||
|
?.filter(i => i.show)
|
||||||
|
.reduce((pre, next, index) => {
|
||||||
|
const keys = ['measures', 'target', 'ranges']
|
||||||
|
if (keys[index]) pre[keys[index]] = next
|
||||||
|
return pre
|
||||||
|
}, {}) as Record<string, SeriesFormatter>
|
||||||
|
|
||||||
|
const tooltip = {
|
||||||
|
shared: true,
|
||||||
|
showMarkers: true,
|
||||||
|
customItems(originalItems) {
|
||||||
|
if (!tooltipAttr.seriesTooltipFormatter?.length) return originalItems
|
||||||
|
|
||||||
|
const result = []
|
||||||
|
const data = options.data.find(item => item.title === originalItems[0].title)
|
||||||
|
Object.keys(formatterMap).forEach(key => {
|
||||||
|
if (key === '记录数*') return
|
||||||
|
const formatter = formatterMap[key]
|
||||||
|
if (formatter) {
|
||||||
|
if (key !== 'ranges') {
|
||||||
|
let value = 0
|
||||||
|
if (chart.yAxis[0].id === chart.yAxisExt[0].id) {
|
||||||
|
value = valueFormatter(parseFloat(data['target'] as string), formatter.formatterCfg)
|
||||||
|
} else {
|
||||||
|
value = valueFormatter(parseFloat(data[key] as string), formatter.formatterCfg)
|
||||||
|
}
|
||||||
|
const name = isEmpty(formatter.chartShowName)
|
||||||
|
? formatter.name
|
||||||
|
: formatter.chartShowName
|
||||||
|
result.push({ ...originalItems[0], color: bullet.bar[key].fill, name, value })
|
||||||
|
} else {
|
||||||
|
const ranges = data.ranges
|
||||||
|
const isDynamic = bullet.bar.ranges.showType === 'dynamic'
|
||||||
|
ranges.forEach((range, index) => {
|
||||||
|
const value = valueFormatter(
|
||||||
|
parseFloat(isDynamic ? data.minRanges[0] : (range as string)),
|
||||||
|
formatter.formatterCfg
|
||||||
|
)
|
||||||
|
let name = ''
|
||||||
|
let color: string | string[]
|
||||||
|
if (bullet.bar.ranges.showType === 'dynamic') {
|
||||||
|
name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName
|
||||||
|
color = bullet.bar[key].fill
|
||||||
|
} else {
|
||||||
|
const customRange = bullet.bar.ranges.fixedRange[index].name
|
||||||
|
name = customRange
|
||||||
|
? customRange
|
||||||
|
: isEmpty(formatter.chartShowName)
|
||||||
|
? formatter.name
|
||||||
|
: formatter.chartShowName
|
||||||
|
color = bullet.bar[key].fixedRange[index].fill
|
||||||
|
}
|
||||||
|
result.push({ ...originalItems[0], color, name, value })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const dynamicTooltipValue = chart.data.data.find(
|
||||||
|
d => d.field === originalItems[0]['title']
|
||||||
|
)?.dynamicTooltipValue
|
||||||
|
if (dynamicTooltipValue.length > 0) {
|
||||||
|
dynamicTooltipValue.forEach(dy => {
|
||||||
|
const q = tooltipAttr.seriesTooltipFormatter.filter(i => i.id === dy.fieldId)
|
||||||
|
if (q && q.length > 0) {
|
||||||
|
const value = valueFormatter(parseFloat(dy.value as string), q[0].formatterCfg)
|
||||||
|
const name = isEmpty(q[0].chartShowName) ? q[0].name : q[0].chartShowName
|
||||||
|
result.push({ color: 'grey', name, value })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
container: getTooltipContainer(`tooltip-${chart.id}`),
|
||||||
|
itemTpl: TOOLTIP_TPL,
|
||||||
|
enterable: true
|
||||||
|
}
|
||||||
|
return { ...options, tooltip }
|
||||||
|
}
|
||||||
|
|
||||||
|
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||||
|
chart.customAttr.label.position = 'middle'
|
||||||
|
chart.customStyle.yAxis.splitLine.show = false
|
||||||
|
return super.setupDefaultOptions(chart)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setupOptions(chart: Chart, options: BulletOptions): BulletOptions {
|
||||||
|
return flow(
|
||||||
|
this.configTheme,
|
||||||
|
this.configBasicStyle,
|
||||||
|
this.configMisc,
|
||||||
|
this.configXAxis,
|
||||||
|
this.configYAxis,
|
||||||
|
this.configLabel,
|
||||||
|
this.configLegend,
|
||||||
|
this.configTooltip
|
||||||
|
)(chart, options, {}, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装子弹图数据
|
||||||
|
* @param chart
|
||||||
|
*/
|
||||||
|
function mergeBulletData(chart): any[] {
|
||||||
|
// 先根据维度分组,再根据指标字段组装成子弹图的格式
|
||||||
|
const groupedData = chart.data.data.reduce((acc, item) => {
|
||||||
|
const field = item.field
|
||||||
|
if (!acc[field]) {
|
||||||
|
acc[field] = []
|
||||||
|
}
|
||||||
|
acc[field].push(item)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
const result = []
|
||||||
|
// 组装子弹图数据,每个维度对应一个子弹图
|
||||||
|
Object.keys(groupedData).forEach(field => {
|
||||||
|
const items = groupedData[field]
|
||||||
|
// 初始化子弹图条目结构
|
||||||
|
const entry = {
|
||||||
|
title: field,
|
||||||
|
ranges: [],
|
||||||
|
measures: [],
|
||||||
|
target: [],
|
||||||
|
dimensionList: items[0].dimensionList,
|
||||||
|
quotaList: []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防止指标相同时无数据有可能会导致数据不一致
|
||||||
|
items.forEach(item => {
|
||||||
|
const quotaId = item.quotaList[0]?.id
|
||||||
|
const v = item.value || 0
|
||||||
|
if (quotaId === chart.yAxis[0]?.id) {
|
||||||
|
entry.measures.push(v)
|
||||||
|
}
|
||||||
|
if (quotaId === chart.yAxisExt[0]?.id) {
|
||||||
|
entry.target.push(v)
|
||||||
|
}
|
||||||
|
if (quotaId === chart.extBubble[0]?.id) {
|
||||||
|
entry.ranges.push(v)
|
||||||
|
}
|
||||||
|
entry.quotaList.push(item.quotaList[0])
|
||||||
|
})
|
||||||
|
// 对数据进行累加
|
||||||
|
const ranges = chart.extBubble[0]?.id
|
||||||
|
? [].concat(entry.ranges?.reduce((acc, curr) => acc + curr, 0))
|
||||||
|
: []
|
||||||
|
const target = [].concat(entry.target?.reduce((acc, curr) => acc + curr, 0))
|
||||||
|
const measures = [].concat(entry.measures?.reduce((acc, curr) => acc + curr, 0))
|
||||||
|
const bulletData = {
|
||||||
|
...entry,
|
||||||
|
measures: measures,
|
||||||
|
target: target,
|
||||||
|
ranges: ranges,
|
||||||
|
quotaList: [...entry.quotaList],
|
||||||
|
minRanges: ranges,
|
||||||
|
originalRanges: ranges,
|
||||||
|
originalTarget: target
|
||||||
|
}
|
||||||
|
result.push(bulletData)
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
@ -6,6 +6,7 @@ import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar'
|
|||||||
import {
|
import {
|
||||||
configAxisLabelLengthLimit,
|
configAxisLabelLengthLimit,
|
||||||
configPlotTooltipEvent,
|
configPlotTooltipEvent,
|
||||||
|
configRoundAngle,
|
||||||
getPadding,
|
getPadding,
|
||||||
getTooltipContainer,
|
getTooltipContainer,
|
||||||
setGradientColor,
|
setGradientColor,
|
||||||
@ -101,6 +102,17 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
|
|||||||
const newChart = new Bar(container, options)
|
const newChart = new Bar(container, options)
|
||||||
|
|
||||||
newChart.on('interval:click', action)
|
newChart.on('interval:click', action)
|
||||||
|
if (options.label) {
|
||||||
|
newChart.on('label:click', e => {
|
||||||
|
action({
|
||||||
|
x: e.x,
|
||||||
|
y: e.y,
|
||||||
|
data: {
|
||||||
|
data: e.target.attrs.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
configPlotTooltipEvent(chart, newChart)
|
configPlotTooltipEvent(chart, newChart)
|
||||||
configAxisLabelLengthLimit(chart, newChart)
|
configAxisLabelLengthLimit(chart, newChart)
|
||||||
return newChart
|
return newChart
|
||||||
@ -135,7 +147,10 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
|
|||||||
tickCount: axisValue.splitCount
|
tickCount: axisValue.splitCount
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { ...tmpOptions, ...axis }
|
// 根据axis的最小值,过滤options中的data数据,过滤掉小于最小值的数据
|
||||||
|
const { data } = options
|
||||||
|
const newData = data.filter(item => item.value >= axisValue.min)
|
||||||
|
return { ...tmpOptions, data: newData, ...axis }
|
||||||
}
|
}
|
||||||
return tmpOptions
|
return tmpOptions
|
||||||
}
|
}
|
||||||
@ -157,19 +172,9 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
|
|||||||
color
|
color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (basicStyle.radiusColumnBar === 'roundAngle') {
|
|
||||||
const barStyle = {
|
|
||||||
radius: [
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius
|
|
||||||
]
|
|
||||||
}
|
|
||||||
options = {
|
options = {
|
||||||
...options,
|
...options,
|
||||||
barStyle
|
...configRoundAngle(chart, 'barStyle')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let barWidthRatio
|
let barWidthRatio
|
||||||
@ -234,6 +239,7 @@ export class HorizontalBar extends G2PlotChartView<BarOptions, Bar> {
|
|||||||
attrs: {
|
attrs: {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
|
data,
|
||||||
text: value,
|
text: value,
|
||||||
textAlign: 'start',
|
textAlign: 'start',
|
||||||
textBaseline: 'top',
|
textBaseline: 'top',
|
||||||
@ -316,8 +322,24 @@ export class HorizontalStackBar extends HorizontalBar {
|
|||||||
baseOptions.label.style.fill = labelAttr.color
|
baseOptions.label.style.fill = labelAttr.color
|
||||||
const label = {
|
const label = {
|
||||||
...baseOptions.label,
|
...baseOptions.label,
|
||||||
formatter: function (param: Datum) {
|
formatter: function (data: Datum) {
|
||||||
return valueFormatter(param.value, labelAttr.labelFormatter)
|
const value = valueFormatter(data.value, labelAttr.labelFormatter)
|
||||||
|
const group = new Group({})
|
||||||
|
group.addShape({
|
||||||
|
type: 'text',
|
||||||
|
attrs: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
data,
|
||||||
|
text: value,
|
||||||
|
textAlign: 'start',
|
||||||
|
textBaseline: 'top',
|
||||||
|
fontSize: labelAttr.fontSize,
|
||||||
|
fontFamily: chart.fontFamily,
|
||||||
|
fill: labelAttr.color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -435,11 +457,29 @@ export class HorizontalPercentageStackBar extends HorizontalStackBar {
|
|||||||
const l = parseJson(customAttr).label
|
const l = parseJson(customAttr).label
|
||||||
const label = {
|
const label = {
|
||||||
...baseOptions.label,
|
...baseOptions.label,
|
||||||
formatter: function (param: Datum) {
|
formatter: function (data: Datum) {
|
||||||
if (!param.value) {
|
let value = data.value
|
||||||
return '0%'
|
if (value) {
|
||||||
|
value = (Math.round(value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%'
|
||||||
|
} else {
|
||||||
|
value = '0%'
|
||||||
}
|
}
|
||||||
return (Math.round(param.value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%'
|
const group = new Group({})
|
||||||
|
group.addShape({
|
||||||
|
type: 'text',
|
||||||
|
attrs: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
data,
|
||||||
|
text: value,
|
||||||
|
textAlign: 'start',
|
||||||
|
textBaseline: 'top',
|
||||||
|
fontSize: l.fontSize,
|
||||||
|
fontFamily: chart.fontFamily,
|
||||||
|
fill: l.color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -3,8 +3,8 @@ import { flow, hexColorToRGBA, parseJson } from '../../../util'
|
|||||||
import {
|
import {
|
||||||
configAxisLabelLengthLimit,
|
configAxisLabelLengthLimit,
|
||||||
configPlotTooltipEvent,
|
configPlotTooltipEvent,
|
||||||
|
configRoundAngle,
|
||||||
getTooltipContainer,
|
getTooltipContainer,
|
||||||
getTooltipItemConditionColor,
|
|
||||||
setGradientColor,
|
setGradientColor,
|
||||||
TOOLTIP_TPL
|
TOOLTIP_TPL
|
||||||
} from '../../common/common_antv'
|
} from '../../common/common_antv'
|
||||||
@ -66,7 +66,7 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
|||||||
'fontSize',
|
'fontSize',
|
||||||
'axisForm',
|
'axisForm',
|
||||||
'axisLabel',
|
'axisLabel',
|
||||||
'position',
|
// 'position',
|
||||||
'showLengthLimit'
|
'showLengthLimit'
|
||||||
],
|
],
|
||||||
'function-cfg': ['emptyDataStrategy'],
|
'function-cfg': ['emptyDataStrategy'],
|
||||||
@ -166,6 +166,7 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (basicStyle.gradient) {
|
if (basicStyle.gradient) {
|
||||||
|
// eslint-disable-next-line
|
||||||
color1 = color1.map((ele, _index) => {
|
color1 = color1.map((ele, _index) => {
|
||||||
return setGradientColor(ele, true, 0)
|
return setGradientColor(ele, true, 0)
|
||||||
})
|
})
|
||||||
@ -184,19 +185,9 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (basicStyle.radiusColumnBar === 'roundAngle') {
|
|
||||||
const barStyle = {
|
|
||||||
radius: [
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius
|
|
||||||
]
|
|
||||||
}
|
|
||||||
options = {
|
options = {
|
||||||
...options,
|
...options,
|
||||||
barStyle
|
...configRoundAngle(chart, 'barStyle')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let barWidthRatio
|
let barWidthRatio
|
||||||
@ -297,12 +288,31 @@ export class ProgressBar extends G2PlotChartView<BarOptions, G2Progress> {
|
|||||||
if (!baseOption.yAxis) {
|
if (!baseOption.yAxis) {
|
||||||
return baseOption
|
return baseOption
|
||||||
}
|
}
|
||||||
if (baseOption.yAxis.position === 'left') {
|
baseOption.yAxis.position = 'bottom'
|
||||||
|
const yAxis = parseJson(chart.customStyle).yAxis
|
||||||
|
if (yAxis.axisLabel.show) {
|
||||||
|
const rotate = yAxis.axisLabel.rotate
|
||||||
|
let textAlign = 'end'
|
||||||
|
let textBaseline = 'middle'
|
||||||
|
if (Math.abs(rotate) > 75) {
|
||||||
|
textAlign = 'center'
|
||||||
|
}
|
||||||
|
if (rotate > 75) {
|
||||||
|
textBaseline = 'top'
|
||||||
|
}
|
||||||
|
if (rotate < -75) {
|
||||||
|
textBaseline = 'bottom'
|
||||||
|
}
|
||||||
|
baseOption.yAxis.label.style.textBaseline = textBaseline
|
||||||
|
baseOption.yAxis.label.style.textAlign = textAlign
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (baseOption.yAxis.position === 'left') {
|
||||||
baseOption.yAxis.position = 'bottom'
|
baseOption.yAxis.position = 'bottom'
|
||||||
}
|
}
|
||||||
if (baseOption.yAxis.position === 'right') {
|
if (baseOption.yAxis.position === 'right') {
|
||||||
baseOption.yAxis.position = 'top'
|
baseOption.yAxis.position = 'top'
|
||||||
}
|
}*/
|
||||||
return baseOption
|
return baseOption
|
||||||
}
|
}
|
||||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||||
|
@ -6,6 +6,7 @@ import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar'
|
|||||||
import {
|
import {
|
||||||
configAxisLabelLengthLimit,
|
configAxisLabelLengthLimit,
|
||||||
configPlotTooltipEvent,
|
configPlotTooltipEvent,
|
||||||
|
configRoundAngle,
|
||||||
getPadding,
|
getPadding,
|
||||||
getTooltipContainer,
|
getTooltipContainer,
|
||||||
setGradientColor,
|
setGradientColor,
|
||||||
@ -22,6 +23,7 @@ import {
|
|||||||
import { Datum } from '@antv/g2plot/esm/types/common'
|
import { Datum } from '@antv/g2plot/esm/types/common'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
|
import { Group } from '@antv/g-canvas'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const DEFAULT_DATA = []
|
const DEFAULT_DATA = []
|
||||||
@ -170,6 +172,17 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
|
|||||||
const newChart = new BarClass(container, options)
|
const newChart = new BarClass(container, options)
|
||||||
|
|
||||||
newChart.on('interval:click', action)
|
newChart.on('interval:click', action)
|
||||||
|
if (options.label) {
|
||||||
|
newChart.on('label:click', e => {
|
||||||
|
action({
|
||||||
|
x: e.x,
|
||||||
|
y: e.y,
|
||||||
|
data: {
|
||||||
|
data: e.target.attrs.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
configPlotTooltipEvent(chart, newChart)
|
configPlotTooltipEvent(chart, newChart)
|
||||||
configAxisLabelLengthLimit(chart, newChart)
|
configAxisLabelLengthLimit(chart, newChart)
|
||||||
return newChart
|
return newChart
|
||||||
@ -309,19 +322,10 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (basicStyle.radiusColumnBar === 'roundAngle') {
|
|
||||||
const barStyle = {
|
|
||||||
radius: [
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius,
|
|
||||||
basicStyle.columnBarRightAngleRadius
|
|
||||||
]
|
|
||||||
}
|
|
||||||
options = {
|
options = {
|
||||||
...options,
|
...options,
|
||||||
barStyle
|
...configRoundAngle(chart, 'barStyle')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let barWidthRatio
|
let barWidthRatio
|
||||||
const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio
|
const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio
|
||||||
@ -391,7 +395,22 @@ export class RangeBar extends G2PlotChartView<BarOptions, Bar> {
|
|||||||
valueFormatter(param.values[1], labelAttr.labelFormatter)
|
valueFormatter(param.values[1], labelAttr.labelFormatter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
const group = new Group({})
|
||||||
|
group.addShape({
|
||||||
|
type: 'text',
|
||||||
|
attrs: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
data: param,
|
||||||
|
text: res,
|
||||||
|
textAlign: 'start',
|
||||||
|
textBaseline: 'top',
|
||||||
|
fontSize: labelAttr.fontSize,
|
||||||
|
fontFamily: chart.fontFamily,
|
||||||
|
fill: labelAttr.color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -72,7 +72,8 @@ export class Waterfall extends G2PlotChartView<WaterfallOptions, G2Waterfall> {
|
|||||||
'axisForm',
|
'axisForm',
|
||||||
'axisLabel',
|
'axisLabel',
|
||||||
'axisLabelFormatter',
|
'axisLabelFormatter',
|
||||||
'showLengthLimit'
|
'showLengthLimit',
|
||||||
|
'axisLine'
|
||||||
],
|
],
|
||||||
threshold: ['lineThreshold']
|
threshold: ['lineThreshold']
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
|
|||||||
'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'],
|
'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'],
|
||||||
'tooltip-selector': [
|
'tooltip-selector': [
|
||||||
...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
||||||
'seriesTooltipFormatter'
|
'seriesTooltipFormatter',
|
||||||
|
'carousel'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
axis: AxisType[] = [...LINE_AXIS_TYPE]
|
axis: AxisType[] = [...LINE_AXIS_TYPE]
|
||||||
@ -103,8 +104,8 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
|
|||||||
|
|
||||||
async drawChart(drawOptions: G2PlotDrawOptions<G2Area>): Promise<G2Area> {
|
async drawChart(drawOptions: G2PlotDrawOptions<G2Area>): Promise<G2Area> {
|
||||||
const { chart, container, action } = drawOptions
|
const { chart, container, action } = drawOptions
|
||||||
if (!chart.data?.data?.length) {
|
|
||||||
chart.container = container
|
chart.container = container
|
||||||
|
if (!chart.data?.data?.length) {
|
||||||
clearExtremum(chart)
|
clearExtremum(chart)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -147,7 +148,7 @@ export class Area extends G2PlotChartView<AreaOptions, G2Area> {
|
|||||||
fields: [],
|
fields: [],
|
||||||
...tmpOptions.label,
|
...tmpOptions.label,
|
||||||
layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout,
|
layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout,
|
||||||
formatter: (data: Datum, _point) => {
|
formatter: (data: Datum) => {
|
||||||
if (data.EXTREME) {
|
if (data.EXTREME) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@ -305,7 +306,7 @@ export class StackArea extends Area {
|
|||||||
propertyInner = {
|
propertyInner = {
|
||||||
...this['propertyInner'],
|
...this['propertyInner'],
|
||||||
'label-selector': ['vPosition', 'fontSize', 'color', 'labelFormatter'],
|
'label-selector': ['vPosition', 'fontSize', 'color', 'labelFormatter'],
|
||||||
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show']
|
'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show', 'carousel']
|
||||||
}
|
}
|
||||||
axisConfig = {
|
axisConfig = {
|
||||||
...this['axisConfig'],
|
...this['axisConfig'],
|
||||||
|
@ -10,10 +10,12 @@ import {
|
|||||||
TOOLTIP_TPL
|
TOOLTIP_TPL
|
||||||
} from '../../common/common_antv'
|
} from '../../common/common_antv'
|
||||||
import {
|
import {
|
||||||
|
convertToAlphaColor,
|
||||||
flow,
|
flow,
|
||||||
getLineConditions,
|
getLineConditions,
|
||||||
getLineLabelColorByCondition,
|
getLineLabelColorByCondition,
|
||||||
hexColorToRGBA,
|
hexColorToRGBA,
|
||||||
|
isAlphaColor,
|
||||||
parseJson,
|
parseJson,
|
||||||
setUpGroupSeriesColor
|
setUpGroupSeriesColor
|
||||||
} from '@/views/chart/components/js/util'
|
} from '@/views/chart/components/js/util'
|
||||||
@ -43,8 +45,10 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
|
|||||||
'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'],
|
'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'],
|
||||||
'tooltip-selector': [
|
'tooltip-selector': [
|
||||||
...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
||||||
'seriesTooltipFormatter'
|
'seriesTooltipFormatter',
|
||||||
]
|
'carousel'
|
||||||
|
],
|
||||||
|
'legend-selector': [...LINE_EDITOR_PROPERTY_INNER['legend-selector'], 'legendSort']
|
||||||
}
|
}
|
||||||
axis: AxisType[] = [...LINE_AXIS_TYPE, 'xAxisExt']
|
axis: AxisType[] = [...LINE_AXIS_TYPE, 'xAxisExt']
|
||||||
axisConfig = {
|
axisConfig = {
|
||||||
@ -66,8 +70,8 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
|
|||||||
}
|
}
|
||||||
async drawChart(drawOptions: G2PlotDrawOptions<G2Line>): Promise<G2Line> {
|
async drawChart(drawOptions: G2PlotDrawOptions<G2Line>): Promise<G2Line> {
|
||||||
const { chart, action, container } = drawOptions
|
const { chart, action, container } = drawOptions
|
||||||
if (!chart.data?.data?.length) {
|
|
||||||
chart.container = container
|
chart.container = container
|
||||||
|
if (!chart.data?.data?.length) {
|
||||||
clearExtremum(chart)
|
clearExtremum(chart)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -146,7 +150,7 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
|
|||||||
fields: [],
|
fields: [],
|
||||||
...tmpOptions.label,
|
...tmpOptions.label,
|
||||||
layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout,
|
layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout,
|
||||||
formatter: (data: Datum, _point) => {
|
formatter: (data: Datum) => {
|
||||||
if (data.EXTREME) {
|
if (data.EXTREME) {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
@ -321,17 +325,30 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
|
|||||||
if (sort?.length) {
|
if (sort?.length) {
|
||||||
// 用值域限定排序,有可能出现新数据但是未出现在图表上,所以这边要遍历一下子维度,加到后面,让新数据显示出来
|
// 用值域限定排序,有可能出现新数据但是未出现在图表上,所以这边要遍历一下子维度,加到后面,让新数据显示出来
|
||||||
const data = optionTmp.data
|
const data = optionTmp.data
|
||||||
data?.forEach(d => {
|
const cats =
|
||||||
const cat = d['category']
|
data?.reduce((p, n) => {
|
||||||
if (cat && !sort.includes(cat)) {
|
const cat = n['category']
|
||||||
sort.push(cat)
|
if (cat && !p.includes(cat)) {
|
||||||
|
p.push(cat)
|
||||||
}
|
}
|
||||||
})
|
return p
|
||||||
|
}, []) || []
|
||||||
|
const values = sort.reduce((p, n) => {
|
||||||
|
if (cats.includes(n)) {
|
||||||
|
const index = cats.indexOf(n)
|
||||||
|
if (index !== -1) {
|
||||||
|
cats.splice(index, 1)
|
||||||
|
}
|
||||||
|
p.push(n)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}, [])
|
||||||
|
cats.length > 0 && values.push(...cats)
|
||||||
optionTmp.meta = {
|
optionTmp.meta = {
|
||||||
...optionTmp.meta,
|
...optionTmp.meta,
|
||||||
category: {
|
category: {
|
||||||
type: 'cat',
|
type: 'cat',
|
||||||
values: sort
|
values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -351,6 +368,56 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
|
|||||||
fill: style.stroke
|
fill: style.stroke
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const { sort, customSort, icon } = customStyle.legend
|
||||||
|
if (sort && sort !== 'none' && chart.xAxisExt.length) {
|
||||||
|
const customAttr = parseJson(chart.customAttr)
|
||||||
|
const { basicStyle } = customAttr
|
||||||
|
const seriesMap =
|
||||||
|
basicStyle.seriesColor?.reduce((p, n) => {
|
||||||
|
p[n.id] = n
|
||||||
|
return p
|
||||||
|
}, {}) || {}
|
||||||
|
const dupCheck = new Set()
|
||||||
|
const items = optionTmp.data?.reduce((arr, item) => {
|
||||||
|
if (!dupCheck.has(item.category)) {
|
||||||
|
const fill =
|
||||||
|
seriesMap[item.category]?.color ??
|
||||||
|
optionTmp.color[dupCheck.size % optionTmp.color.length]
|
||||||
|
dupCheck.add(item.category)
|
||||||
|
arr.push({
|
||||||
|
name: item.category,
|
||||||
|
value: item.category,
|
||||||
|
marker: {
|
||||||
|
symbol: icon,
|
||||||
|
style: {
|
||||||
|
r: size,
|
||||||
|
fill: isAlphaColor(fill) ? fill : convertToAlphaColor(fill, basicStyle.alpha)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}, [])
|
||||||
|
if (sort !== 'custom') {
|
||||||
|
items.sort((a, b) => {
|
||||||
|
return sort !== 'desc' ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const tmp = []
|
||||||
|
;(customSort || []).forEach(item => {
|
||||||
|
const index = items.findIndex(i => i.name === item)
|
||||||
|
if (index !== -1) {
|
||||||
|
tmp.push(items[index])
|
||||||
|
items.splice(index, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
items.unshift(...tmp)
|
||||||
|
}
|
||||||
|
optionTmp.legend.items = items
|
||||||
|
if (xAxisExt?.customSort?.length > 0) {
|
||||||
|
delete optionTmp.meta?.category.values
|
||||||
|
}
|
||||||
|
}
|
||||||
return optionTmp
|
return optionTmp
|
||||||
}
|
}
|
||||||
protected setupOptions(chart: Chart, options: LineOptions): LineOptions {
|
protected setupOptions(chart: Chart, options: LineOptions): LineOptions {
|
||||||
|
@ -440,7 +440,6 @@ export class StockLine extends G2PlotChartView<MixOptions, Mix> {
|
|||||||
|
|
||||||
protected configTooltip(chart: Chart, options: MixOptions): MixOptions {
|
protected configTooltip(chart: Chart, options: MixOptions): MixOptions {
|
||||||
const tooltipAttr = parseJson(chart.customAttr).tooltip
|
const tooltipAttr = parseJson(chart.customAttr).tooltip
|
||||||
const xAxis = chart.xAxis
|
|
||||||
const newPlots = []
|
const newPlots = []
|
||||||
const linePlotList = options.plots.filter(item => item.type === 'line')
|
const linePlotList = options.plots.filter(item => item.type === 'line')
|
||||||
linePlotList.forEach(item => {
|
linePlotList.forEach(item => {
|
||||||
|
@ -74,7 +74,7 @@ export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
|||||||
})
|
})
|
||||||
// 处理空数据, 只要有一个指标是空数据,就不显示图表
|
// 处理空数据, 只要有一个指标是空数据,就不显示图表
|
||||||
const hasNoneData = chart.data?.series.some(s => !s.data?.[0])
|
const hasNoneData = chart.data?.series.some(s => !s.data?.[0])
|
||||||
this.configEmptyDataStyle(newChart, hasNoneData ? [] : [1], container)
|
this.configEmptyDataStyle(hasNoneData ? [] : [1], container, newChart)
|
||||||
if (hasNoneData) {
|
if (hasNoneData) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -402,7 +402,8 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
content.push(name)
|
content.push(name)
|
||||||
}
|
}
|
||||||
if (label.showQuota) {
|
if (label.showQuota) {
|
||||||
areaMap[name] && content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter))
|
;(areaMap[name] || areaMap[name] === 0) &&
|
||||||
|
content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter))
|
||||||
}
|
}
|
||||||
item.properties['_DE_LABEL_'] = content.join('\n\n')
|
item.properties['_DE_LABEL_'] = content.join('\n\n')
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
export const MAP_EDITOR_PROPERTY: EditorProperty[] = [
|
export const MAP_EDITOR_PROPERTY: EditorProperty[] = [
|
||||||
'background-overall-component',
|
'background-overall-component',
|
||||||
'border-style',
|
'border-style',
|
||||||
@ -51,6 +55,28 @@ export const MAP_AXIS_TYPE: AxisType[] = [
|
|||||||
'extTooltip'
|
'extTooltip'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const gaodeMapStyleOptions = [
|
||||||
|
{ name: t('chart.map_style_normal'), value: 'normal' },
|
||||||
|
{ name: t('chart.map_style_darkblue'), value: 'darkblue' },
|
||||||
|
{ name: t('chart.map_style_light'), value: 'light' },
|
||||||
|
{ name: t('chart.map_style_dark'), value: 'dark' },
|
||||||
|
{ name: t('chart.map_style_fresh'), value: 'fresh' },
|
||||||
|
{ name: t('chart.map_style_grey'), value: 'grey' },
|
||||||
|
{ name: t('chart.map_style_blue'), value: 'blue' },
|
||||||
|
{ name: t('commons.custom'), value: 'custom' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export const tdtMapStyleOptions = [
|
||||||
|
{ name: t('chart.map_style_normal'), value: 'normal' },
|
||||||
|
{ name: t('chart.map_style_dark'), value: 'black' },
|
||||||
|
{ name: t('chart.map_style_darkblue'), value: 'indigo' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export const qqMapStyleOptions = [
|
||||||
|
{ name: t('chart.map_style_normal'), value: 'normal' },
|
||||||
|
{ name: t('commons.custom'), value: 'custom' }
|
||||||
|
]
|
||||||
|
|
||||||
export declare type MapMouseEvent = MouseEvent & {
|
export declare type MapMouseEvent = MouseEvent & {
|
||||||
feature: GeoJSON.Feature
|
feature: GeoJSON.Feature
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,16 @@ import {
|
|||||||
import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common'
|
import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common'
|
||||||
import { hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
|
import { hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
|
||||||
import { deepCopy } from '@/utils/utils'
|
import { deepCopy } from '@/utils/utils'
|
||||||
import { GaodeMap } from '@antv/l7-maps'
|
|
||||||
import { Scene } from '@antv/l7-scene'
|
import { Scene } from '@antv/l7-scene'
|
||||||
import { LineLayer } from '@antv/l7-layers'
|
import { LineLayer } from '@antv/l7-layers'
|
||||||
import { PointLayer } from '@antv/l7-layers'
|
import { PointLayer } from '@antv/l7-layers'
|
||||||
import { mapRendered, mapRendering } from '@/views/chart/components/js/panel/common/common_antv'
|
import {
|
||||||
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
getMapCenter,
|
||||||
|
getMapScene,
|
||||||
|
getMapStyle,
|
||||||
|
mapRendered,
|
||||||
|
qqMapRendered
|
||||||
|
} from '@/views/chart/components/js/panel/common/common_antv'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,103 +92,16 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
|||||||
const xAxisExt = deepCopy(chart.xAxisExt)
|
const xAxisExt = deepCopy(chart.xAxisExt)
|
||||||
const { basicStyle, misc } = deepCopy(parseJson(chart.customAttr))
|
const { basicStyle, misc } = deepCopy(parseJson(chart.customAttr))
|
||||||
|
|
||||||
let center: [number, number] = [
|
|
||||||
DEFAULT_BASIC_STYLE.mapCenter.longitude,
|
|
||||||
DEFAULT_BASIC_STYLE.mapCenter.latitude
|
|
||||||
]
|
|
||||||
if (basicStyle.autoFit === false) {
|
|
||||||
center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
|
|
||||||
}
|
|
||||||
let mapStyle = basicStyle.mapStyleUrl
|
|
||||||
if (basicStyle.mapStyle !== 'custom') {
|
|
||||||
mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
|
|
||||||
}
|
|
||||||
const mapKey = await this.getMapKey()
|
const mapKey = await this.getMapKey()
|
||||||
|
const mapStyle = getMapStyle(mapKey, basicStyle)
|
||||||
// 底层
|
// 底层
|
||||||
const chartObj = drawOption.chartObj as unknown as L7Wrapper<L7Config, Scene>
|
const chartObj = drawOption.chartObj as unknown as L7Wrapper<L7Config, Scene>
|
||||||
let scene = chartObj?.getScene()
|
let scene = chartObj?.getScene()
|
||||||
if(scene){
|
|
||||||
if (scene.getLayers()?.length) {
|
const center = getMapCenter(basicStyle)
|
||||||
await scene.removeAllLayer()
|
scene = await getMapScene(chart, scene, container, mapKey, basicStyle, misc, mapStyle, center)
|
||||||
scene.setPitch(misc.mapPitch)
|
|
||||||
}
|
this.configZoomButton(chart, scene, mapKey)
|
||||||
}
|
|
||||||
if (mapStyle.indexOf('Satellite') == -1) {
|
|
||||||
scene = new Scene({
|
|
||||||
id: container,
|
|
||||||
logoVisible: false,
|
|
||||||
map: new GaodeMap({
|
|
||||||
token: mapKey?.key ?? undefined,
|
|
||||||
style: mapStyle,
|
|
||||||
pitch: misc.mapPitch,
|
|
||||||
center,
|
|
||||||
zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined,
|
|
||||||
showLabel: !(basicStyle.showLabel === false),
|
|
||||||
WebGLParams: {
|
|
||||||
preserveDrawingBuffer: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
scene = new Scene({
|
|
||||||
id: container,
|
|
||||||
logoVisible: false,
|
|
||||||
map: new GaodeMap({
|
|
||||||
token: mapKey?.key ?? undefined,
|
|
||||||
style: mapStyle,
|
|
||||||
features: ['bg', 'road'], // 必须开启路网层
|
|
||||||
plugin: ['AMap.TileLayer.Satellite'], // 显式声明卫星图层
|
|
||||||
WebGLParams: {
|
|
||||||
preserveDrawingBuffer: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// if (!scene) {
|
|
||||||
// scene = new Scene({
|
|
||||||
// id: container,
|
|
||||||
// logoVisible: false,
|
|
||||||
// map: new GaodeMap({
|
|
||||||
// token: mapKey?.key ?? undefined,
|
|
||||||
// style: mapStyle,
|
|
||||||
// pitch: misc.mapPitch,
|
|
||||||
// center: basicStyle.autoFit === false ? center : undefined,
|
|
||||||
// zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined,
|
|
||||||
// showLabel: !(basicStyle.showLabel === false),
|
|
||||||
// WebGLParams: {
|
|
||||||
// preserveDrawingBuffer: true
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// } else {
|
|
||||||
// if (scene.getLayers()?.length) {
|
|
||||||
// await scene.removeAllLayer()
|
|
||||||
// scene.setPitch(misc.mapPitch)
|
|
||||||
// scene.setMapStyle(mapStyle)
|
|
||||||
// scene.map.showLabel = !(basicStyle.showLabel === false)
|
|
||||||
// }
|
|
||||||
// if (basicStyle.autoFit === false) {
|
|
||||||
// scene.setZoomAndCenter(basicStyle.zoomLevel, center)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
mapRendering(container)
|
|
||||||
if (mapStyle.indexOf('Satellite') == -1) {
|
|
||||||
scene.once('loaded', () => {
|
|
||||||
mapRendered(container)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
scene.once('loaded', () => {
|
|
||||||
// 创建卫星图层实例
|
|
||||||
const satelliteLayer = new AMap.TileLayer.Satellite()
|
|
||||||
// 与矢量图层叠加显示
|
|
||||||
satelliteLayer.setMap(scene.map)
|
|
||||||
mapRendered(container)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// scene.once('loaded', () => {
|
|
||||||
// mapRendered(container)
|
|
||||||
// })
|
|
||||||
this.configZoomButton(chart, scene)
|
|
||||||
if (xAxis?.length < 2 || xAxisExt?.length < 2) {
|
if (xAxis?.length < 2 || xAxisExt?.length < 2) {
|
||||||
return new L7Wrapper(scene, undefined)
|
return new L7Wrapper(scene, undefined)
|
||||||
}
|
}
|
||||||
@ -195,6 +112,11 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
|||||||
configList[0].once('inited', () => {
|
configList[0].once('inited', () => {
|
||||||
mapRendered(container)
|
mapRendered(container)
|
||||||
})
|
})
|
||||||
|
for (let i = 0; i < configList.length; i++) {
|
||||||
|
configList[i].on('inited', () => {
|
||||||
|
qqMapRendered(scene)
|
||||||
|
})
|
||||||
|
}
|
||||||
return new L7Wrapper(scene, configList)
|
return new L7Wrapper(scene, configList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,11 +8,16 @@ import {
|
|||||||
import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common'
|
import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common'
|
||||||
import { flow, parseJson } from '@/views/chart/components/js/util'
|
import { flow, parseJson } from '@/views/chart/components/js/util'
|
||||||
import { deepCopy } from '@/utils/utils'
|
import { deepCopy } from '@/utils/utils'
|
||||||
import { GaodeMap } from '@antv/l7-maps'
|
|
||||||
import { Scene } from '@antv/l7-scene'
|
import { Scene } from '@antv/l7-scene'
|
||||||
import { HeatmapLayer } from '@antv/l7-layers'
|
import { HeatmapLayer } from '@antv/l7-layers'
|
||||||
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
import { mapRendered, mapRendering } from '@/views/chart/components/js/panel/common/common_antv'
|
import {
|
||||||
|
getMapCenter,
|
||||||
|
getMapScene,
|
||||||
|
getMapStyle,
|
||||||
|
mapRendered,
|
||||||
|
qqMapRendered
|
||||||
|
} from '@/views/chart/components/js/panel/common/common_antv'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,94 +74,31 @@ export class HeatMap extends L7ChartView<Scene, L7Config> {
|
|||||||
basicStyle = parseJson(chart.customAttr).basicStyle
|
basicStyle = parseJson(chart.customAttr).basicStyle
|
||||||
miscStyle = parseJson(chart.customAttr).misc
|
miscStyle = parseJson(chart.customAttr).misc
|
||||||
}
|
}
|
||||||
let center: [number, number] = [
|
|
||||||
DEFAULT_BASIC_STYLE.mapCenter.longitude,
|
|
||||||
DEFAULT_BASIC_STYLE.mapCenter.latitude
|
|
||||||
]
|
|
||||||
if (basicStyle.autoFit === false) {
|
|
||||||
center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
|
|
||||||
}
|
|
||||||
let mapStyle = basicStyle.mapStyleUrl
|
|
||||||
if (basicStyle.mapStyle !== 'custom') {
|
|
||||||
mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
|
|
||||||
}
|
|
||||||
const mapKey = await this.getMapKey()
|
const mapKey = await this.getMapKey()
|
||||||
|
const mapStyle = getMapStyle(mapKey, basicStyle)
|
||||||
// 底层
|
// 底层
|
||||||
const chartObj = drawOption.chartObj as unknown as L7Wrapper<L7Config, Scene>
|
const chartObj = drawOption.chartObj as unknown as L7Wrapper<L7Config, Scene>
|
||||||
let scene = chartObj?.getScene()
|
let scene = chartObj?.getScene()
|
||||||
if(scene){
|
const center = getMapCenter(basicStyle)
|
||||||
if (scene.getLayers()?.length) {
|
scene = await getMapScene(
|
||||||
await scene.removeAllLayer()
|
chart,
|
||||||
scene.setPitch(miscStyle.mapPitch)
|
scene,
|
||||||
}
|
container,
|
||||||
}
|
mapKey,
|
||||||
|
basicStyle,
|
||||||
if (mapStyle.indexOf('Satellite') == -1) {
|
miscStyle,
|
||||||
scene = new Scene({
|
mapStyle,
|
||||||
id: container,
|
center
|
||||||
logoVisible: false,
|
)
|
||||||
map: new GaodeMap({
|
this.configZoomButton(chart, scene, mapKey)
|
||||||
token: mapKey?.key ?? undefined,
|
|
||||||
style: mapStyle,
|
|
||||||
pitch: miscStyle.mapPitch,
|
|
||||||
center,
|
|
||||||
zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined,
|
|
||||||
showLabel: !(basicStyle.showLabel === false),
|
|
||||||
WebGLParams: {
|
|
||||||
preserveDrawingBuffer: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
scene = new Scene({
|
|
||||||
id: container,
|
|
||||||
logoVisible: false,
|
|
||||||
map: new GaodeMap({
|
|
||||||
token: mapKey?.key ?? undefined,
|
|
||||||
style: mapStyle,
|
|
||||||
features: ['bg', 'road'], // 必须开启路网层
|
|
||||||
plugin: ['AMap.TileLayer.Satellite'], // 显式声明卫星图层
|
|
||||||
WebGLParams: {
|
|
||||||
preserveDrawingBuffer: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// } else {
|
|
||||||
// // if (scene.getLayers()?.length) {
|
|
||||||
// await scene.removeAllLayer()
|
|
||||||
// scene.setPitch(miscStyle.mapPitch)
|
|
||||||
// scene.setMapStyle(mapStyle)
|
|
||||||
// scene.map.showLabel = !(basicStyle.showLabel === false)
|
|
||||||
// if (basicStyle.autoFit === false) {
|
|
||||||
// scene.setZoomAndCenter(basicStyle.zoomLevel, center)
|
|
||||||
// }
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
mapRendering(container)
|
|
||||||
if (mapStyle.indexOf('Satellite') == -1) {
|
|
||||||
scene.once('loaded', () => {
|
|
||||||
mapRendered(container)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
scene.once('loaded', () => {
|
|
||||||
// 创建卫星图层实例
|
|
||||||
const satelliteLayer = new AMap.TileLayer.Satellite()
|
|
||||||
// 与矢量图层叠加显示
|
|
||||||
satelliteLayer.setMap(scene.map)
|
|
||||||
mapRendered(container)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.configZoomButton(chart, scene)
|
|
||||||
if (xAxis?.length < 2 || yAxis?.length < 1) {
|
if (xAxis?.length < 2 || yAxis?.length < 1) {
|
||||||
return new L7Wrapper(scene, undefined)
|
return new L7Wrapper(scene, undefined)
|
||||||
}
|
}
|
||||||
const config: L7Config = new HeatmapLayer({
|
const config: L7Config = new HeatmapLayer({
|
||||||
name: 'line',
|
name: 'line',
|
||||||
blend: 'normal',
|
blend: 'normal',
|
||||||
autoFit: !(basicStyle.autoFit === false)
|
autoFit: !(basicStyle.autoFit === false),
|
||||||
|
zIndex: 10
|
||||||
})
|
})
|
||||||
.source(chart.data?.data, {
|
.source(chart.data?.data, {
|
||||||
parser: {
|
parser: {
|
||||||
@ -177,6 +119,13 @@ export class HeatMap extends L7ChartView<Scene, L7Config> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
config.once('inited', () => {
|
||||||
|
mapRendered(container)
|
||||||
|
})
|
||||||
|
config.on('inited', () => {
|
||||||
|
qqMapRendered(scene)
|
||||||
|
})
|
||||||
|
|
||||||
return new L7Wrapper(scene, config)
|
return new L7Wrapper(scene, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +157,11 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
data = filterChartDataByRange(sourceData, maxValue, minValue)
|
data = filterChartDataByRange(sourceData, maxValue, minValue)
|
||||||
|
if (chart.drill) {
|
||||||
|
getMaxAndMinValueByData(sourceData, 'value', 0, 0, (max, min) => {
|
||||||
|
data = filterChartDataByRange(sourceData, max, min)
|
||||||
|
})
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data = sourceData
|
data = sourceData
|
||||||
}
|
}
|
||||||
@ -301,7 +306,8 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
content.push(name)
|
content.push(name)
|
||||||
}
|
}
|
||||||
if (label.showQuota) {
|
if (label.showQuota) {
|
||||||
areaMap[name] && content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter))
|
;(areaMap[name] || areaMap[name] === 0) &&
|
||||||
|
content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter))
|
||||||
}
|
}
|
||||||
item.properties['_DE_LABEL_'] = content.join('\n\n')
|
item.properties['_DE_LABEL_'] = content.join('\n\n')
|
||||||
}
|
}
|
||||||
@ -346,11 +352,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
return listDom
|
return listDom
|
||||||
}
|
}
|
||||||
|
|
||||||
private customConfigLegend(
|
private customConfigLegend(chart: Chart, options: ChoroplethOptions): ChoroplethOptions {
|
||||||
chart: Chart,
|
|
||||||
options: ChoroplethOptions,
|
|
||||||
context: Record<string, any>
|
|
||||||
): ChoroplethOptions {
|
|
||||||
const { basicStyle, misc } = parseJson(chart.customAttr)
|
const { basicStyle, misc } = parseJson(chart.customAttr)
|
||||||
const colors = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha))
|
const colors = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha))
|
||||||
if (basicStyle.suspension === false && basicStyle.showZoom === undefined) {
|
if (basicStyle.suspension === false && basicStyle.showZoom === undefined) {
|
||||||
@ -420,14 +422,14 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
const isLessThanMin = range[0] < ranges[0][0] && range[1] < ranges[0][0]
|
const isLessThanMin = range[0] < ranges[0][0] && range[1] < ranges[0][0]
|
||||||
let rangeColor = colors[colorIndex]
|
let rangeColor = colors[colorIndex]
|
||||||
if (isLessThanMin) {
|
if (isLessThanMin) {
|
||||||
rangeColor = hexColorToRGBA(basicStyle.areaBaseColor, basicStyle.alpha)
|
rangeColor = basicStyle.areaBaseColor
|
||||||
}
|
}
|
||||||
items.push({
|
items.push({
|
||||||
value: tmpRange,
|
value: tmpRange,
|
||||||
color: rangeColor
|
color: rangeColor
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
customLegend['customContent'] = (_: string, _items: CategoryLegendListItem[]) => {
|
customLegend['customContent'] = () => {
|
||||||
if (items?.length) {
|
if (items?.length) {
|
||||||
return this.createLegendCustomContent(items)
|
return this.createLegendCustomContent(items)
|
||||||
}
|
}
|
||||||
@ -435,13 +437,16 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
}
|
}
|
||||||
options.color['value'] = ({ value }) => {
|
options.color['value'] = ({ value }) => {
|
||||||
const item = items.find(item => value >= item.value[0] && value <= item.value[1])
|
const item = items.find(item => value >= item.value[0] && value <= item.value[1])
|
||||||
return item ? item.color : hexColorToRGBA(basicStyle.areaBaseColor, basicStyle.alpha)
|
return item ? item.color : basicStyle.areaBaseColor
|
||||||
}
|
}
|
||||||
options.color.scale.domain = [ranges[0][0], ranges[ranges.length - 1][1]]
|
options.color.scale.domain = [ranges[0][0], ranges[ranges.length - 1][1]]
|
||||||
} else {
|
} else {
|
||||||
customLegend['customContent'] = (_: string, items: CategoryLegendListItem[]) => {
|
customLegend['customContent'] = (_: string, items: CategoryLegendListItem[]) => {
|
||||||
const showItems = items?.length > 30 ? items.slice(0, 30) : items
|
const showItems = items?.length > 30 ? items.slice(0, 30) : items
|
||||||
if (showItems?.length) {
|
if (showItems?.length) {
|
||||||
|
if (showItems.length === 1) {
|
||||||
|
showItems[0].value = options.color.scale.domain.slice(0, 2)
|
||||||
|
}
|
||||||
return this.createLegendCustomContent(showItems)
|
return this.createLegendCustomContent(showItems)
|
||||||
}
|
}
|
||||||
return ''
|
return ''
|
||||||
@ -508,7 +513,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
content.push(area.name)
|
content.push(area.name)
|
||||||
}
|
}
|
||||||
if (label.showQuota) {
|
if (label.showQuota) {
|
||||||
areaMap[area.name] &&
|
;(areaMap[area.name] || areaMap[area.name] === 0) &&
|
||||||
content.push(valueFormatter(areaMap[area.name].value, label.quotaLabelFormatter))
|
content.push(valueFormatter(areaMap[area.name].value, label.quotaLabelFormatter))
|
||||||
}
|
}
|
||||||
labelLocation.push({
|
labelLocation.push({
|
||||||
@ -567,6 +572,9 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
const head = originalItem.properties
|
const head = originalItem.properties
|
||||||
|
if (!head) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
const { adcode } = head
|
const { adcode } = head
|
||||||
const areaName = subAreaMap['156' + adcode]
|
const areaName = subAreaMap['156' + adcode]
|
||||||
const valItem = areaMap[areaName]
|
const valItem = areaMap[areaName]
|
||||||
|
@ -13,13 +13,17 @@ import {
|
|||||||
svgStrToUrl
|
svgStrToUrl
|
||||||
} from '@/views/chart/components/js/util'
|
} from '@/views/chart/components/js/util'
|
||||||
import { deepCopy } from '@/utils/utils'
|
import { deepCopy } from '@/utils/utils'
|
||||||
import { GaodeMap } from '@antv/l7-maps'
|
|
||||||
import { Scene } from '@antv/l7-scene'
|
import { Scene } from '@antv/l7-scene'
|
||||||
import { PointLayer } from '@antv/l7-layers'
|
import { PointLayer } from '@antv/l7-layers'
|
||||||
import { LayerPopup, Popup } from '@antv/l7'
|
import { LayerPopup, Popup } from '@antv/l7'
|
||||||
import { mapRendered, mapRendering } from '@/views/chart/components/js/panel/common/common_antv'
|
import {
|
||||||
|
getMapCenter,
|
||||||
|
getMapScene,
|
||||||
|
getMapStyle,
|
||||||
|
mapRendered,
|
||||||
|
qqMapRendered
|
||||||
|
} from '@/views/chart/components/js/panel/common/common_antv'
|
||||||
import { configCarouselTooltip } from '@/views/chart/components/js/panel/charts/map/tooltip-carousel'
|
import { configCarouselTooltip } from '@/views/chart/components/js/panel/charts/map/tooltip-carousel'
|
||||||
import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
|
||||||
import { filter } from 'lodash-es'
|
import { filter } from 'lodash-es'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -102,18 +106,10 @@ export class SymbolicMap extends L7ChartView<Scene, L7Config> {
|
|||||||
miscStyle = parseJson(chart.customAttr).misc
|
miscStyle = parseJson(chart.customAttr).misc
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapStyle = basicStyle.mapStyleUrl
|
|
||||||
if (basicStyle.mapStyle !== 'custom') {
|
|
||||||
mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
|
|
||||||
}
|
|
||||||
const mapKey = await this.getMapKey()
|
const mapKey = await this.getMapKey()
|
||||||
let center: [number, number] = [
|
const mapStyle = getMapStyle(mapKey, basicStyle)
|
||||||
DEFAULT_BASIC_STYLE.mapCenter.longitude,
|
|
||||||
DEFAULT_BASIC_STYLE.mapCenter.latitude
|
let center = getMapCenter(basicStyle)
|
||||||
]
|
|
||||||
if (basicStyle.autoFit === false) {
|
|
||||||
center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
|
|
||||||
}
|
|
||||||
// 联动时,聚焦到数据点,多个取第一个
|
// 联动时,聚焦到数据点,多个取第一个
|
||||||
if (
|
if (
|
||||||
chart.chartExtRequest?.linkageFilters?.length &&
|
chart.chartExtRequest?.linkageFilters?.length &&
|
||||||
@ -128,38 +124,18 @@ export class SymbolicMap extends L7ChartView<Scene, L7Config> {
|
|||||||
}
|
}
|
||||||
const chartObj = drawOption.chartObj as unknown as L7Wrapper<L7Config, Scene>
|
const chartObj = drawOption.chartObj as unknown as L7Wrapper<L7Config, Scene>
|
||||||
let scene = chartObj?.getScene()
|
let scene = chartObj?.getScene()
|
||||||
if (!scene) {
|
scene = await getMapScene(
|
||||||
scene = new Scene({
|
chart,
|
||||||
id: container,
|
scene,
|
||||||
logoVisible: false,
|
container,
|
||||||
map: new GaodeMap({
|
mapKey,
|
||||||
token: mapKey?.key ?? undefined,
|
basicStyle,
|
||||||
style: mapStyle,
|
miscStyle,
|
||||||
pitch: miscStyle.mapPitch,
|
mapStyle,
|
||||||
center,
|
center
|
||||||
zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined,
|
)
|
||||||
showLabel: !(basicStyle.showLabel === false),
|
|
||||||
WebGLParams: {
|
this.configZoomButton(chart, scene, mapKey)
|
||||||
preserveDrawingBuffer: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
if (scene.getLayers()?.length) {
|
|
||||||
await scene.removeAllLayer()
|
|
||||||
scene.setPitch(miscStyle.mapPitch)
|
|
||||||
scene.setMapStyle(mapStyle)
|
|
||||||
scene.map.showLabel = !(basicStyle.showLabel === false)
|
|
||||||
}
|
|
||||||
if (basicStyle.autoFit === false) {
|
|
||||||
scene.setZoomAndCenter(basicStyle.zoomLevel, center)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mapRendering(container)
|
|
||||||
scene.once('loaded', () => {
|
|
||||||
mapRendered(container)
|
|
||||||
})
|
|
||||||
this.configZoomButton(chart, scene)
|
|
||||||
if (xAxis?.length < 2) {
|
if (xAxis?.length < 2) {
|
||||||
return new L7Wrapper(scene, undefined)
|
return new L7Wrapper(scene, undefined)
|
||||||
}
|
}
|
||||||
@ -171,9 +147,13 @@ export class SymbolicMap extends L7ChartView<Scene, L7Config> {
|
|||||||
scene.addPopup(tooltipLayer)
|
scene.addPopup(tooltipLayer)
|
||||||
}
|
}
|
||||||
this.buildLabel(chart, configList)
|
this.buildLabel(chart, configList)
|
||||||
|
symbolicLayer.once('inited', () => {
|
||||||
|
mapRendered(container)
|
||||||
|
})
|
||||||
symbolicLayer.on('inited', () => {
|
symbolicLayer.on('inited', () => {
|
||||||
chart.container = container
|
chart.container = container
|
||||||
configCarouselTooltip(chart, symbolicLayer, symbolicLayer.sourceOption.data, scene)
|
configCarouselTooltip(chart, symbolicLayer, symbolicLayer.sourceOption.data, scene)
|
||||||
|
qqMapRendered(scene)
|
||||||
})
|
})
|
||||||
symbolicLayer.on('click', ev => {
|
symbolicLayer.on('click', ev => {
|
||||||
const data = ev.feature
|
const data = ev.feature
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
} from '@/views/chart/components/js/panel/types/impl/g2plot'
|
} from '@/views/chart/components/js/panel/types/impl/g2plot'
|
||||||
import type { DualAxes, DualAxesOptions } from '@antv/g2plot/esm/plots/dual-axes'
|
import type { DualAxes, DualAxesOptions } from '@antv/g2plot/esm/plots/dual-axes'
|
||||||
import {
|
import {
|
||||||
|
configRoundAngle,
|
||||||
configPlotTooltipEvent,
|
configPlotTooltipEvent,
|
||||||
getAnalyse,
|
getAnalyse,
|
||||||
getLabel,
|
getLabel,
|
||||||
@ -42,6 +43,7 @@ import {
|
|||||||
} from '@/views/chart/components/editor/util/chart'
|
} from '@/views/chart/components/editor/util/chart'
|
||||||
import type { Options } from '@antv/g2plot/esm'
|
import type { Options } from '@antv/g2plot/esm'
|
||||||
import { Group } from '@antv/g-canvas'
|
import { Group } from '@antv/g-canvas'
|
||||||
|
import { extremumEvt } from '@/views/chart/components/js/extremumUitl'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const DEFAULT_DATA = []
|
const DEFAULT_DATA = []
|
||||||
@ -56,7 +58,8 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
|||||||
'label-selector': ['vPosition', 'seriesLabelFormatter'],
|
'label-selector': ['vPosition', 'seriesLabelFormatter'],
|
||||||
'tooltip-selector': [
|
'tooltip-selector': [
|
||||||
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
||||||
'seriesTooltipFormatter'
|
'seriesTooltipFormatter',
|
||||||
|
'carousel'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
axis: AxisType[] = [...CHART_MIX_AXIS_TYPE, 'xAxisExtRight', 'yAxisExt']
|
axis: AxisType[] = [...CHART_MIX_AXIS_TYPE, 'xAxisExtRight', 'yAxisExt']
|
||||||
@ -94,6 +97,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
|||||||
|
|
||||||
async drawChart(drawOptions: G2PlotDrawOptions<DualAxes>): Promise<DualAxes> {
|
async drawChart(drawOptions: G2PlotDrawOptions<DualAxes>): Promise<DualAxes> {
|
||||||
const { chart, action, container } = drawOptions
|
const { chart, action, container } = drawOptions
|
||||||
|
chart.container = container
|
||||||
if (!chart.data?.left?.data?.length && !chart.data?.right?.data?.length) {
|
if (!chart.data?.left?.data?.length && !chart.data?.right?.data?.length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -117,7 +121,6 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
|||||||
valueExt: d.value
|
valueExt: d.value
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// options
|
// options
|
||||||
const initOptions: DualAxesOptions = {
|
const initOptions: DualAxesOptions = {
|
||||||
data: [data1, data2],
|
data: [data1, data2],
|
||||||
@ -127,6 +130,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
|||||||
geometryOptions: [
|
geometryOptions: [
|
||||||
{
|
{
|
||||||
geometry: data1Type,
|
geometry: data1Type,
|
||||||
|
marginRatio: 0,
|
||||||
color: [],
|
color: [],
|
||||||
isGroup: isGroup,
|
isGroup: isGroup,
|
||||||
isStack: isStack,
|
isStack: isStack,
|
||||||
@ -174,6 +178,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
|||||||
|
|
||||||
newChart.on('point:click', action)
|
newChart.on('point:click', action)
|
||||||
newChart.on('interval:click', action)
|
newChart.on('interval:click', action)
|
||||||
|
extremumEvt(newChart, chart, options, container)
|
||||||
configPlotTooltipEvent(chart, newChart)
|
configPlotTooltipEvent(chart, newChart)
|
||||||
return newChart
|
return newChart
|
||||||
}
|
}
|
||||||
@ -292,18 +297,9 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
|||||||
tempOption.geometryOptions[1].smooth = smooth
|
tempOption.geometryOptions[1].smooth = smooth
|
||||||
tempOption.geometryOptions[1].point = point
|
tempOption.geometryOptions[1].point = point
|
||||||
tempOption.geometryOptions[1].lineStyle = lineStyle
|
tempOption.geometryOptions[1].lineStyle = lineStyle
|
||||||
|
tempOption.geometryOptions[0] = {
|
||||||
if (s.radiusColumnBar === 'roundAngle') {
|
...tempOption.geometryOptions[0],
|
||||||
const columnStyle = {
|
...configRoundAngle(chart, 'columnStyle')
|
||||||
radius: [
|
|
||||||
s.columnBarRightAngleRadius,
|
|
||||||
s.columnBarRightAngleRadius,
|
|
||||||
s.columnBarRightAngleRadius,
|
|
||||||
s.columnBarRightAngleRadius
|
|
||||||
]
|
|
||||||
}
|
|
||||||
tempOption.geometryOptions[0].columnStyle = columnStyle
|
|
||||||
tempOption.geometryOptions[1].columnStyle = columnStyle
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +324,7 @@ export class ColumnLineMix extends G2PlotChartView<DualAxesOptions, DualAxes> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||||
const { customAttr, senior } = chart
|
const { senior } = chart
|
||||||
if (
|
if (
|
||||||
senior.functionCfg.emptyDataStrategy == undefined ||
|
senior.functionCfg.emptyDataStrategy == undefined ||
|
||||||
senior.functionCfg.emptyDataStrategy === 'ignoreData'
|
senior.functionCfg.emptyDataStrategy === 'ignoreData'
|
||||||
@ -670,7 +666,8 @@ export class GroupColumnLineMix extends ColumnLineMix {
|
|||||||
'label-selector': ['vPosition', 'seriesLabelFormatter'],
|
'label-selector': ['vPosition', 'seriesLabelFormatter'],
|
||||||
'tooltip-selector': [
|
'tooltip-selector': [
|
||||||
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
||||||
'seriesTooltipFormatter'
|
'seriesTooltipFormatter',
|
||||||
|
'carousel'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
axisConfig = {
|
axisConfig = {
|
||||||
@ -782,7 +779,8 @@ export class StackColumnLineMix extends ColumnLineMix {
|
|||||||
'label-selector': ['vPosition', 'seriesLabelFormatter'],
|
'label-selector': ['vPosition', 'seriesLabelFormatter'],
|
||||||
'tooltip-selector': [
|
'tooltip-selector': [
|
||||||
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
||||||
'seriesTooltipFormatter'
|
'seriesTooltipFormatter',
|
||||||
|
'carousel'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
axisConfig = {
|
axisConfig = {
|
||||||
@ -895,7 +893,8 @@ export class DualLineMix extends ColumnLineMix {
|
|||||||
'label-selector': ['seriesLabelFormatter'],
|
'label-selector': ['seriesLabelFormatter'],
|
||||||
'tooltip-selector': [
|
'tooltip-selector': [
|
||||||
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'],
|
||||||
'seriesTooltipFormatter'
|
'seriesTooltipFormatter',
|
||||||
|
'carousel'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
axisConfig = {
|
axisConfig = {
|
||||||
|
@ -69,7 +69,7 @@ export class CirclePacking extends G2PlotChartView<CirclePackingOptions, G2Circl
|
|||||||
if (chart?.data?.data?.length) {
|
if (chart?.data?.data?.length) {
|
||||||
// data
|
// data
|
||||||
const data = chart.data.data
|
const data = chart.data.data
|
||||||
const { xAxis, yAxis, drillFields } = chart
|
const { yAxis } = chart
|
||||||
const ySort = yAxis[0]?.sort ?? 'none'
|
const ySort = yAxis[0]?.sort ?? 'none'
|
||||||
const sort = {
|
const sort = {
|
||||||
sort: (a, b) =>
|
sort: (a, b) =>
|
||||||
@ -123,7 +123,7 @@ export class CirclePacking extends G2PlotChartView<CirclePackingOptions, G2Circl
|
|||||||
'@antv/g2plot/esm/plots/circle-packing'
|
'@antv/g2plot/esm/plots/circle-packing'
|
||||||
)
|
)
|
||||||
const newChart = new G2CirclePacking(container, options)
|
const newChart = new G2CirclePacking(container, options)
|
||||||
newChart.on('point:click', param => {
|
newChart.on('element:click', param => {
|
||||||
const pointData = param?.data?.data
|
const pointData = param?.data?.data
|
||||||
if (pointData?.name === t('commons.all')) {
|
if (pointData?.name === t('commons.all')) {
|
||||||
return
|
return
|
||||||
@ -177,7 +177,7 @@ export class CirclePacking extends G2PlotChartView<CirclePackingOptions, G2Circl
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
offsetY: 5,
|
offsetY: 5,
|
||||||
layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout,
|
layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout,
|
||||||
formatter: (d: Datum, _point) => {
|
formatter: (d: Datum) => {
|
||||||
return d.children.length === 0 ? d.name : ''
|
return d.children.length === 0 ? d.name : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
getScaleValue
|
getScaleValue
|
||||||
} from '@/views/chart/components/editor/util/chart'
|
} from '@/views/chart/components/editor/util/chart'
|
||||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||||
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
|
import { setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { merge } from 'lodash-es'
|
import { merge } from 'lodash-es'
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
|||||||
// options
|
// options
|
||||||
const initOptions: GaugeOptions = {
|
const initOptions: GaugeOptions = {
|
||||||
percent: 0,
|
percent: 0,
|
||||||
appendPadding: getPadding(chart),
|
appendPadding: [0, 10, 15, 10],
|
||||||
axis: {
|
axis: {
|
||||||
tickInterval: 0.2,
|
tickInterval: 0.2,
|
||||||
label: {
|
label: {
|
||||||
@ -109,8 +109,10 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const hasNoneData = chart.data?.series.some(s => !s.data?.[0])
|
const hasNoneData = chart.data?.series.some(
|
||||||
this.configEmptyDataStyle(newChart, hasNoneData ? [] : [1], container)
|
s => s.data?.[0] === undefined || s.data?.[0] === null
|
||||||
|
)
|
||||||
|
this.configEmptyDataStyle(hasNoneData ? [] : [1], container, newChart)
|
||||||
if (hasNoneData) {
|
if (hasNoneData) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@ export class IndicatorChartView extends AbstractChartView {
|
|||||||
'indicator-value-selector',
|
'indicator-value-selector',
|
||||||
'indicator-name-selector',
|
'indicator-name-selector',
|
||||||
'threshold',
|
'threshold',
|
||||||
'function-cfg'
|
'function-cfg',
|
||||||
|
'linkage'
|
||||||
]
|
]
|
||||||
propertyInner: EditorPropertyInner = {
|
propertyInner: EditorPropertyInner = {
|
||||||
'background-overall-component': ['all'],
|
'background-overall-component': ['all'],
|
||||||
|
@ -13,7 +13,8 @@ import {
|
|||||||
configPlotTooltipEvent,
|
configPlotTooltipEvent,
|
||||||
configYaxisTitleLengthLimit,
|
configYaxisTitleLengthLimit,
|
||||||
getTooltipContainer,
|
getTooltipContainer,
|
||||||
TOOLTIP_TPL
|
TOOLTIP_TPL,
|
||||||
|
getPadding
|
||||||
} from '../../common/common_antv'
|
} from '../../common/common_antv'
|
||||||
import { DEFAULT_LEGEND_STYLE } from '@/views/chart/components/editor/util/chart'
|
import { DEFAULT_LEGEND_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
|
|
||||||
@ -209,7 +210,7 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
|||||||
data: data,
|
data: data,
|
||||||
xField: 'yAxis',
|
xField: 'yAxis',
|
||||||
yField: 'yAxisExt',
|
yField: 'yAxisExt',
|
||||||
appendPadding: 30,
|
appendPadding: getPadding(chart),
|
||||||
pointStyle: {
|
pointStyle: {
|
||||||
fillOpacity: 0.8,
|
fillOpacity: 0.8,
|
||||||
stroke: '#bbb'
|
stroke: '#bbb'
|
||||||
@ -476,7 +477,6 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
|||||||
this.configLegend,
|
this.configLegend,
|
||||||
this.configXAxis,
|
this.configXAxis,
|
||||||
this.configYAxis,
|
this.configYAxis,
|
||||||
this.configAnalyse,
|
|
||||||
this.configSlider,
|
this.configSlider,
|
||||||
this.configBasicStyle
|
this.configBasicStyle
|
||||||
)(chart, options, {}, this)
|
)(chart, options, {}, this)
|
||||||
|
@ -14,6 +14,8 @@ import {
|
|||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { defaults, isEmpty } from 'lodash-es'
|
import { defaults, isEmpty } from 'lodash-es'
|
||||||
import { DEFAULT_LEGEND_STYLE } from '@/views/chart/components/editor/util/chart'
|
import { DEFAULT_LEGEND_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||||
|
import { type Datum } from '@antv/g2plot/esm'
|
||||||
|
import { Group } from '@antv/g-canvas'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
/**
|
/**
|
||||||
@ -144,6 +146,17 @@ export class Scatter extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
|||||||
const { Scatter: G2Scatter } = await import('@antv/g2plot/esm/plots/scatter')
|
const { Scatter: G2Scatter } = await import('@antv/g2plot/esm/plots/scatter')
|
||||||
const newChart = new G2Scatter(container, options)
|
const newChart = new G2Scatter(container, options)
|
||||||
newChart.on('point:click', action)
|
newChart.on('point:click', action)
|
||||||
|
if (options.label) {
|
||||||
|
newChart.on('label:click', e => {
|
||||||
|
action({
|
||||||
|
x: e.x,
|
||||||
|
y: e.y,
|
||||||
|
data: {
|
||||||
|
data: e.target.attrs.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
configPlotTooltipEvent(chart, newChart)
|
configPlotTooltipEvent(chart, newChart)
|
||||||
return newChart
|
return newChart
|
||||||
}
|
}
|
||||||
@ -277,6 +290,41 @@ export class Scatter extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
|||||||
return optionTmp
|
return optionTmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected configLabel(chart: Chart, options: ScatterOptions): ScatterOptions {
|
||||||
|
const tmpOption = super.configLabel(chart, options)
|
||||||
|
if (!tmpOption.label) {
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
const { label: labelAttr } = parseJson(chart.customAttr)
|
||||||
|
tmpOption.label.style.fill = labelAttr.color
|
||||||
|
const label = {
|
||||||
|
...tmpOption.label,
|
||||||
|
formatter: function (data: Datum) {
|
||||||
|
const value = valueFormatter(data.value, labelAttr.labelFormatter)
|
||||||
|
const group = new Group({})
|
||||||
|
group.addShape({
|
||||||
|
type: 'text',
|
||||||
|
attrs: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
data,
|
||||||
|
text: value,
|
||||||
|
textAlign: 'start',
|
||||||
|
textBaseline: 'top',
|
||||||
|
fontSize: labelAttr.fontSize,
|
||||||
|
fontFamily: chart.fontFamily,
|
||||||
|
fill: labelAttr.color
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...tmpOption,
|
||||||
|
label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected setupOptions(chart: Chart, options: ScatterOptions) {
|
protected setupOptions(chart: Chart, options: ScatterOptions) {
|
||||||
return flow(
|
return flow(
|
||||||
this.configTheme,
|
this.configTheme,
|
||||||
@ -286,7 +334,6 @@ export class Scatter extends G2PlotChartView<ScatterOptions, G2Scatter> {
|
|||||||
this.configLegend,
|
this.configLegend,
|
||||||
this.configXAxis,
|
this.configXAxis,
|
||||||
this.configYAxis,
|
this.configYAxis,
|
||||||
this.configAnalyse,
|
|
||||||
this.configSlider,
|
this.configSlider,
|
||||||
this.configBasicStyle
|
this.configBasicStyle
|
||||||
)(chart, options)
|
)(chart, options)
|
||||||
|
@ -27,19 +27,23 @@ import type { Datum } from '@antv/g2plot/esm/types/common'
|
|||||||
import { add } from 'mathjs'
|
import { add } from 'mathjs'
|
||||||
import isEmpty from 'lodash-es/isEmpty'
|
import isEmpty from 'lodash-es/isEmpty'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
const { t } = useI18n()
|
||||||
const DEFAULT_DATA = []
|
const DEFAULT_DATA = []
|
||||||
export class Pie extends G2PlotChartView<PieOptions, G2Pie> {
|
export class Pie extends G2PlotChartView<PieOptions, G2Pie> {
|
||||||
axis: AxisType[] = PIE_AXIS_TYPE
|
axis: AxisType[] = PIE_AXIS_TYPE
|
||||||
properties = PIE_EDITOR_PROPERTY
|
properties = PIE_EDITOR_PROPERTY
|
||||||
propertyInner: EditorPropertyInner = {
|
propertyInner: EditorPropertyInner = {
|
||||||
...PIE_EDITOR_PROPERTY_INNER,
|
...PIE_EDITOR_PROPERTY_INNER,
|
||||||
'basic-style-selector': ['colors', 'alpha', 'radius', 'topN', 'seriesColor']
|
'basic-style-selector': ['colors', 'alpha', 'radius', 'topN', 'seriesColor'],
|
||||||
|
'tooltip-selector': [...PIE_EDITOR_PROPERTY_INNER['tooltip-selector'], 'carousel']
|
||||||
}
|
}
|
||||||
axisConfig = PIE_AXIS_CONFIG
|
axisConfig = PIE_AXIS_CONFIG
|
||||||
|
|
||||||
async drawChart(drawOptions: G2PlotDrawOptions<G2Pie>): Promise<G2Pie> {
|
async drawChart(drawOptions: G2PlotDrawOptions<G2Pie>): Promise<G2Pie> {
|
||||||
const { chart, container, action } = drawOptions
|
const { chart, container, action } = drawOptions
|
||||||
|
this.configEmptyDataStyle(chart.data?.data, container, null, t('chart.no_data_or_not_positive'))
|
||||||
|
chart.container = container
|
||||||
if (!chart.data?.data?.length) {
|
if (!chart.data?.data?.length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -115,12 +119,22 @@ export class Pie extends G2PlotChartView<PieOptions, G2Pie> {
|
|||||||
field: {
|
field: {
|
||||||
type: 'cat'
|
type: 'cat'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
active: {
|
||||||
|
style: {
|
||||||
|
lineWidth: 2,
|
||||||
|
fillOpacity: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const options = this.setupOptions(chart, initOptions)
|
const options = this.setupOptions(chart, initOptions)
|
||||||
const { Pie: G2Pie } = await import('@antv/g2plot/esm/plots/pie')
|
const { Pie: G2Pie } = await import('@antv/g2plot/esm/plots/pie')
|
||||||
const newChart = new G2Pie(container, options)
|
const newChart = new G2Pie(container, options)
|
||||||
newChart.on('interval:click', action)
|
newChart.on('interval:click', d => {
|
||||||
|
d.data?.data?.field !== customAttr.basicStyle.topNLabel && action(d)
|
||||||
|
})
|
||||||
configPlotTooltipEvent(chart, newChart)
|
configPlotTooltipEvent(chart, newChart)
|
||||||
return newChart
|
return newChart
|
||||||
}
|
}
|
||||||
@ -244,6 +258,7 @@ export class Pie extends G2PlotChartView<PieOptions, G2Pie> {
|
|||||||
},
|
},
|
||||||
container: getTooltipContainer(`tooltip-${chart.id}`),
|
container: getTooltipContainer(`tooltip-${chart.id}`),
|
||||||
itemTpl: TOOLTIP_TPL,
|
itemTpl: TOOLTIP_TPL,
|
||||||
|
shared: true,
|
||||||
enterable: true
|
enterable: true
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -338,7 +353,8 @@ export class Pie extends G2PlotChartView<PieOptions, G2Pie> {
|
|||||||
export class PieDonut extends Pie {
|
export class PieDonut extends Pie {
|
||||||
propertyInner: EditorPropertyInner = {
|
propertyInner: EditorPropertyInner = {
|
||||||
...PIE_EDITOR_PROPERTY_INNER,
|
...PIE_EDITOR_PROPERTY_INNER,
|
||||||
'basic-style-selector': ['colors', 'alpha', 'radius', 'innerRadius', 'topN', 'seriesColor']
|
'basic-style-selector': ['colors', 'alpha', 'radius', 'innerRadius', 'topN', 'seriesColor'],
|
||||||
|
'tooltip-selector': [...PIE_EDITOR_PROPERTY_INNER['tooltip-selector'], 'carousel']
|
||||||
}
|
}
|
||||||
protected configBasicStyle(chart: Chart, options: PieOptions): PieOptions {
|
protected configBasicStyle(chart: Chart, options: PieOptions): PieOptions {
|
||||||
const tmp = super.configBasicStyle(chart, options)
|
const tmp = super.configBasicStyle(chart, options)
|
||||||
|
@ -40,6 +40,7 @@ export class Rose extends G2PlotChartView<RoseOptions, G2Rose> {
|
|||||||
|
|
||||||
async drawChart(drawOptions: G2PlotDrawOptions<G2Rose>): Promise<G2Rose> {
|
async drawChart(drawOptions: G2PlotDrawOptions<G2Rose>): Promise<G2Rose> {
|
||||||
const { chart, container, action } = drawOptions
|
const { chart, container, action } = drawOptions
|
||||||
|
this.configEmptyDataStyle(chart.data?.data, container, null, t('chart.no_data_or_not_positive'))
|
||||||
if (!chart?.data?.data?.length) {
|
if (!chart?.data?.data?.length) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ export const TABLE_EDITOR_PROPERTY: EditorProperty[] = [
|
|||||||
'table-cell-selector',
|
'table-cell-selector',
|
||||||
'title-selector',
|
'title-selector',
|
||||||
'tooltip-selector',
|
'tooltip-selector',
|
||||||
|
'summary-selector',
|
||||||
'function-cfg',
|
'function-cfg',
|
||||||
'threshold',
|
'threshold',
|
||||||
'scroll-cfg',
|
'scroll-cfg',
|
||||||
|
@ -123,7 +123,8 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
|
|||||||
const xFieldExt = xAxisExt[0].dataeaseName
|
const xFieldExt = xAxisExt[0].dataeaseName
|
||||||
const extColorField = extColor[0].dataeaseName
|
const extColorField = extColor[0].dataeaseName
|
||||||
// data
|
// data
|
||||||
const data = cloneDeep(chart.data.tableRow)
|
const tmpData = cloneDeep(chart.data.tableRow)
|
||||||
|
const data = tmpData.filter(cell => cell[xField] && cell[xFieldExt] && cell[extColorField])
|
||||||
data.forEach(i => {
|
data.forEach(i => {
|
||||||
Object.keys(i).forEach(key => {
|
Object.keys(i).forEach(key => {
|
||||||
if (key === '*') {
|
if (key === '*') {
|
||||||
@ -207,6 +208,12 @@ export class TableHeatmap extends G2PlotChartView<HeatmapOptions, Heatmap> {
|
|||||||
return newChart
|
return newChart
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected configTheme(chart: Chart, options: HeatmapOptions): HeatmapOptions {
|
||||||
|
const tmp = super.configTheme(chart, options)
|
||||||
|
tmp.theme.innerLabels.offset = 0
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
|
||||||
protected configBasicStyle(chart: Chart, options: HeatmapOptions): HeatmapOptions {
|
protected configBasicStyle(chart: Chart, options: HeatmapOptions): HeatmapOptions {
|
||||||
const basicStyle = parseJson(chart.customAttr).basicStyle
|
const basicStyle = parseJson(chart.customAttr).basicStyle
|
||||||
const color = basicStyle.colors?.map(ele => {
|
const color = basicStyle.colors?.map(ele => {
|
||||||
|
@ -14,7 +14,7 @@ import { hexColorToRGBA, isAlphaColor, parseJson } from '../../../util'
|
|||||||
import { S2ChartView, S2DrawOptions } from '../../types/impl/s2'
|
import { S2ChartView, S2DrawOptions } from '../../types/impl/s2'
|
||||||
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
|
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { isEqual, isNumber, merge } from 'lodash-es'
|
import { filter, isEqual, isNumber, merge } from 'lodash-es'
|
||||||
import {
|
import {
|
||||||
copyContent,
|
copyContent,
|
||||||
CustomDataCell,
|
CustomDataCell,
|
||||||
@ -22,37 +22,19 @@ import {
|
|||||||
getRowIndex,
|
getRowIndex,
|
||||||
calculateHeaderHeight,
|
calculateHeaderHeight,
|
||||||
SortTooltip,
|
SortTooltip,
|
||||||
configSummaryRow,
|
|
||||||
summaryRowStyle,
|
|
||||||
configEmptyDataStyle,
|
configEmptyDataStyle,
|
||||||
getLeafNodes,
|
getLeafNodes,
|
||||||
getColumns
|
getColumns,
|
||||||
|
drawImage,
|
||||||
|
getSummaryRow,
|
||||||
|
SummaryCell
|
||||||
} from '@/views/chart/components/js/panel/common/common_table'
|
} from '@/views/chart/components/js/panel/common/common_table'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
class ImageCell extends CustomDataCell {
|
class ImageCell extends CustomDataCell {
|
||||||
protected drawTextShape(): void {
|
protected drawTextShape(): void {
|
||||||
const img = new Image()
|
drawImage.apply(this)
|
||||||
const { x, y, width, height, fieldValue } = this.meta
|
|
||||||
img.src = fieldValue as string
|
|
||||||
img.setAttribute('crossOrigin', 'anonymous')
|
|
||||||
img.onload = () => {
|
|
||||||
!this.cfg.children && (this.cfg.children = [])
|
|
||||||
const { width: imgWidth, height: imgHeight } = img
|
|
||||||
const ratio = Math.max(imgWidth / width, imgHeight / height)
|
|
||||||
// 不铺满,部分留白
|
|
||||||
const imgShowWidth = (imgWidth / ratio) * 0.8
|
|
||||||
const imgShowHeight = (imgHeight / ratio) * 0.8
|
|
||||||
this.textShape = this.addShape('image', {
|
|
||||||
attrs: {
|
|
||||||
x: x + (imgShowWidth < width ? (width - imgShowWidth) / 2 : 0),
|
|
||||||
y: y + (imgShowHeight < height ? (height - imgShowHeight) / 2 : 0),
|
|
||||||
width: imgShowWidth,
|
|
||||||
height: imgShowHeight,
|
|
||||||
img
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -75,9 +57,7 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
'alpha',
|
'alpha',
|
||||||
'tablePageMode',
|
'tablePageMode',
|
||||||
'showHoverStyle',
|
'showHoverStyle',
|
||||||
'autoWrap',
|
'autoWrap'
|
||||||
'showSummary',
|
|
||||||
'summaryLabel'
|
|
||||||
],
|
],
|
||||||
'table-cell-selector': [
|
'table-cell-selector': [
|
||||||
...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'],
|
...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'],
|
||||||
@ -85,7 +65,8 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
'tableColumnFreezeHead',
|
'tableColumnFreezeHead',
|
||||||
'tableRowFreezeHead',
|
'tableRowFreezeHead',
|
||||||
'mergeCells'
|
'mergeCells'
|
||||||
]
|
],
|
||||||
|
'summary-selector': ['showSummary', 'summaryLabel']
|
||||||
}
|
}
|
||||||
axis: AxisType[] = ['xAxis', 'filter', 'drill']
|
axis: AxisType[] = ['xAxis', 'filter', 'drill']
|
||||||
axisConfig: AxisConfig = {
|
axisConfig: AxisConfig = {
|
||||||
@ -140,7 +121,7 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if (![2, 3].includes(f.deType) || !isNumber(value)) {
|
if (![2, 3, 4].includes(f.deType) || !isNumber(value)) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
let formatCfg = f.formatterCfg
|
let formatCfg = f.formatterCfg
|
||||||
@ -215,37 +196,6 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0
|
s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0
|
||||||
s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0
|
s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0
|
||||||
}
|
}
|
||||||
// 开启序号之后,第一列就是序号列,修改 label 即可
|
|
||||||
if (s2Options.showSeriesNumber) {
|
|
||||||
let indexLabel = tableHeader.indexLabel
|
|
||||||
if (!indexLabel) {
|
|
||||||
indexLabel = ''
|
|
||||||
}
|
|
||||||
s2Options.layoutCoordinate = (_, __, col) => {
|
|
||||||
if (col.colIndex === 0 && col.rowIndex === 0) {
|
|
||||||
col.label = indexLabel
|
|
||||||
col.value = indexLabel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s2Options.dataCell = viewMeta => {
|
|
||||||
const field = fields.filter(f => f.dataeaseName === viewMeta.valueField)?.[0]
|
|
||||||
if (field?.deType === 7 && chart.showPosition !== 'dialog') {
|
|
||||||
return new ImageCell(viewMeta, viewMeta?.spreadsheet)
|
|
||||||
}
|
|
||||||
if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) {
|
|
||||||
if (tableCell.mergeCells) {
|
|
||||||
viewMeta.fieldValue = getRowIndex(s2Options.mergedCellsInfo, viewMeta)
|
|
||||||
} else {
|
|
||||||
viewMeta.fieldValue =
|
|
||||||
pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 配置文本自动换行参数
|
|
||||||
viewMeta.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap
|
|
||||||
viewMeta.maxLines = basicStyle.maxLines
|
|
||||||
return new CustomDataCell(viewMeta, viewMeta?.spreadsheet)
|
|
||||||
}
|
|
||||||
// tooltip
|
// tooltip
|
||||||
this.configTooltip(chart, s2Options)
|
this.configTooltip(chart, s2Options)
|
||||||
// 合并单元格
|
// 合并单元格
|
||||||
@ -274,12 +224,12 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
return new CustomTableColCell(node, sheet, config)
|
return new CustomTableColCell(node, sheet, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 总计
|
// 序列号和总计行
|
||||||
configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary)
|
this.configSummaryRowAndIndex(chart, pageInfo, s2Options, s2DataConfig)
|
||||||
// 开始渲染
|
// 开始渲染
|
||||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||||
// 总计紧贴在单元格后面
|
// 总计紧贴在单元格后面
|
||||||
summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
|
this.summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
|
||||||
// 开启自动换行
|
// 开启自动换行
|
||||||
if (basicStyle.autoWrap && !tableCell.mergeCells) {
|
if (basicStyle.autoWrap && !tableCell.mergeCells) {
|
||||||
// 调整表头宽度时,计算表头高度
|
// 调整表头宽度时,计算表头高度
|
||||||
@ -417,13 +367,13 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||||
newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||||
newChart.on(S2Event.MERGED_CELLS_HOVER, event => this.showTooltip(newChart, event, meta))
|
newChart.on(S2Event.MERGED_CELLS_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||||
|
// touch
|
||||||
|
this.configTouchEvent(newChart, drawOption, meta)
|
||||||
}
|
}
|
||||||
// header resize
|
// header resize
|
||||||
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev))
|
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev))
|
||||||
// right click
|
// right click
|
||||||
newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta))
|
newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta))
|
||||||
// touch
|
|
||||||
this.configTouchEvent(newChart, drawOption, meta)
|
|
||||||
// theme
|
// theme
|
||||||
const customTheme = this.configTheme(chart)
|
const customTheme = this.configTheme(chart)
|
||||||
newChart.setThemeCfg({ theme: customTheme })
|
newChart.setThemeCfg({ theme: customTheme })
|
||||||
@ -444,6 +394,11 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
const fontStyle = tableCell.isItalic ? 'italic' : 'normal'
|
const fontStyle = tableCell.isItalic ? 'italic' : 'normal'
|
||||||
const fontWeight = tableCell.isBolder === false ? 'normal' : 'bold'
|
const fontWeight = tableCell.isBolder === false ? 'normal' : 'bold'
|
||||||
const mergeCellTheme: S2Theme = {
|
const mergeCellTheme: S2Theme = {
|
||||||
|
dataCell: {
|
||||||
|
cell: {
|
||||||
|
crossBackgroundColor: tableItemBgColor
|
||||||
|
}
|
||||||
|
},
|
||||||
mergedCell: {
|
mergedCell: {
|
||||||
cell: {
|
cell: {
|
||||||
backgroundColor: tableItemBgColor,
|
backgroundColor: tableItemBgColor,
|
||||||
@ -488,6 +443,92 @@ export class TableInfo extends S2ChartView<TableSheet> {
|
|||||||
return theme
|
return theme
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected configSummaryRowAndIndex(
|
||||||
|
chart: Chart,
|
||||||
|
pageInfo: PageInfo,
|
||||||
|
s2Options: S2Options,
|
||||||
|
s2DataConfig: S2DataConfig
|
||||||
|
) {
|
||||||
|
const { tableHeader, basicStyle, tableCell } = parseJson(chart.customAttr)
|
||||||
|
const fields = chart.data?.fields ?? []
|
||||||
|
// 开启序号之后,第一列就是序号列,修改 label 即可
|
||||||
|
if (s2Options.showSeriesNumber) {
|
||||||
|
let indexLabel = tableHeader.indexLabel
|
||||||
|
if (!indexLabel) {
|
||||||
|
indexLabel = ''
|
||||||
|
}
|
||||||
|
s2Options.layoutCoordinate = (_, __, col) => {
|
||||||
|
if (col.colIndex === 0 && col.rowIndex === 0) {
|
||||||
|
col.label = indexLabel
|
||||||
|
col.value = indexLabel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { showSummary, summaryLabel } = basicStyle
|
||||||
|
const data = s2DataConfig.data
|
||||||
|
const xAxis = chart.xAxis
|
||||||
|
if (showSummary && data?.length) {
|
||||||
|
// 设置汇总行高度和表头一致
|
||||||
|
const heightByField = {}
|
||||||
|
heightByField[data.length] = tableHeader.tableTitleHeight
|
||||||
|
s2Options.style.rowCfg = { heightByField }
|
||||||
|
// 计算汇总加入到数据里,冻结最后一行
|
||||||
|
s2Options.frozenTrailingRowCount = 1
|
||||||
|
const axis = filter(xAxis, axis => [2, 3, 4].includes(axis.deType))
|
||||||
|
const summaryObj = getSummaryRow(data, axis, basicStyle.seriesSummary) as any
|
||||||
|
data.push(summaryObj)
|
||||||
|
}
|
||||||
|
s2Options.dataCell = viewMeta => {
|
||||||
|
// 总计行处理
|
||||||
|
if (showSummary && viewMeta.rowIndex === data.length - 1) {
|
||||||
|
if (viewMeta.colIndex === 0) {
|
||||||
|
if (tableHeader.showIndex) {
|
||||||
|
viewMeta.fieldValue = summaryLabel ?? t('chart.total_show')
|
||||||
|
} else {
|
||||||
|
// 第一列不是数值类型的,显示总计
|
||||||
|
if (![2, 3, 4].includes(xAxis?.[0]?.deType)) {
|
||||||
|
viewMeta.fieldValue = summaryLabel ?? t('chart.total_show')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new SummaryCell(viewMeta, viewMeta?.spreadsheet)
|
||||||
|
}
|
||||||
|
const field = fields.find(f => f.dataeaseName === viewMeta.valueField)
|
||||||
|
if (field?.deType === 7 && chart.showPosition !== 'dialog') {
|
||||||
|
return new ImageCell(viewMeta, viewMeta?.spreadsheet)
|
||||||
|
}
|
||||||
|
if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) {
|
||||||
|
if (tableCell.mergeCells) {
|
||||||
|
viewMeta.fieldValue = getRowIndex(s2Options.mergedCellsInfo, viewMeta)
|
||||||
|
} else {
|
||||||
|
viewMeta.fieldValue =
|
||||||
|
pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 配置文本自动换行参数
|
||||||
|
viewMeta.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap
|
||||||
|
viewMeta.maxLines = basicStyle.maxLines
|
||||||
|
return new CustomDataCell(viewMeta, viewMeta?.spreadsheet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected summaryRowStyle(newChart: TableSheet, newData, tableCell, tableHeader, showSummary) {
|
||||||
|
if (!showSummary || !newData.length) return
|
||||||
|
const columns = newChart.dataCfg.fields.columns
|
||||||
|
const showHeader = tableHeader.showTableHeader === true
|
||||||
|
// 不显示表头时,减少一个表头的高度
|
||||||
|
const headerAndSummaryHeight = showHeader ? getMaxTreeDepth(columns) + 1 : 1
|
||||||
|
newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
|
||||||
|
const totalHeight =
|
||||||
|
tableHeader.tableTitleHeight * headerAndSummaryHeight +
|
||||||
|
tableCell.tableItemHeight * (newData.length - 1)
|
||||||
|
if (totalHeight < newChart.container.cfg.height) {
|
||||||
|
newChart.options.height =
|
||||||
|
totalHeight < newChart.container.cfg.height - 8 ? totalHeight + 8 : totalHeight
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super('table-info', [])
|
super('table-info', [])
|
||||||
}
|
}
|
||||||
@ -508,3 +549,17 @@ function getStartPosition(node) {
|
|||||||
}
|
}
|
||||||
return getStartPosition(node.children[0])
|
return getStartPosition(node.children[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMaxTreeDepth(nodes) {
|
||||||
|
if (!nodes?.length) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return Math.max(
|
||||||
|
...nodes.map(node => {
|
||||||
|
if (!node.children?.length) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return getMaxTreeDepth(node.children) + 1
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -2,10 +2,11 @@ import { useI18n } from '@/hooks/web/useI18n'
|
|||||||
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
|
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
|
||||||
import {
|
import {
|
||||||
configEmptyDataStyle,
|
configEmptyDataStyle,
|
||||||
configSummaryRow,
|
|
||||||
copyContent,
|
copyContent,
|
||||||
|
CustomDataCell,
|
||||||
|
getSummaryRow,
|
||||||
SortTooltip,
|
SortTooltip,
|
||||||
summaryRowStyle
|
SummaryCell
|
||||||
} from '@/views/chart/components/js/panel/common/common_table'
|
} from '@/views/chart/components/js/panel/common/common_table'
|
||||||
import { S2ChartView, S2DrawOptions } from '@/views/chart/components/js/panel/types/impl/s2'
|
import { S2ChartView, S2DrawOptions } from '@/views/chart/components/js/panel/types/impl/s2'
|
||||||
import { parseJson } from '@/views/chart/components/js/util'
|
import { parseJson } from '@/views/chart/components/js/util'
|
||||||
@ -19,7 +20,7 @@ import {
|
|||||||
TableSheet,
|
TableSheet,
|
||||||
ViewMeta
|
ViewMeta
|
||||||
} from '@antv/s2'
|
} from '@antv/s2'
|
||||||
import { cloneDeep, isNumber } from 'lodash-es'
|
import { isNumber } from 'lodash-es'
|
||||||
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
|
import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@ -37,8 +38,7 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
|||||||
],
|
],
|
||||||
'basic-style-selector': [
|
'basic-style-selector': [
|
||||||
...TABLE_EDITOR_PROPERTY_INNER['basic-style-selector'],
|
...TABLE_EDITOR_PROPERTY_INNER['basic-style-selector'],
|
||||||
'showSummary',
|
'tablePageMode',
|
||||||
'summaryLabel',
|
|
||||||
'showHoverStyle'
|
'showHoverStyle'
|
||||||
],
|
],
|
||||||
'table-cell-selector': [
|
'table-cell-selector': [
|
||||||
@ -46,7 +46,8 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
|||||||
'tableFreeze',
|
'tableFreeze',
|
||||||
'tableColumnFreezeHead',
|
'tableColumnFreezeHead',
|
||||||
'tableRowFreezeHead'
|
'tableRowFreezeHead'
|
||||||
]
|
],
|
||||||
|
'summary-selector': ['showSummary', 'summaryLabel']
|
||||||
}
|
}
|
||||||
axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter']
|
axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter']
|
||||||
axisConfig: AxisConfig = {
|
axisConfig: AxisConfig = {
|
||||||
@ -66,7 +67,7 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawChart(drawOption: S2DrawOptions<TableSheet>): TableSheet {
|
drawChart(drawOption: S2DrawOptions<TableSheet>): TableSheet {
|
||||||
const { container, chart, action, resizeAction } = drawOption
|
const { container, chart, action, pageInfo, resizeAction } = drawOption
|
||||||
const containerDom = document.getElementById(container)
|
const containerDom = document.getElementById(container)
|
||||||
if (!containerDom) return
|
if (!containerDom) return
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
|||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if (![2, 3].includes(f.deType) || !isNumber(value)) {
|
if (![2, 3, 4].includes(f.deType) || !isNumber(value)) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
let formatCfg = f.formatterCfg
|
let formatCfg = f.formatterCfg
|
||||||
@ -160,19 +161,6 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
|||||||
s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0
|
s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0
|
||||||
s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0
|
s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0
|
||||||
}
|
}
|
||||||
// 开启序号之后,第一列就是序号列,修改 label 即可
|
|
||||||
if (s2Options.showSeriesNumber) {
|
|
||||||
let indexLabel = tableHeader.indexLabel
|
|
||||||
if (!indexLabel) {
|
|
||||||
indexLabel = ''
|
|
||||||
}
|
|
||||||
s2Options.layoutCoordinate = (_, __, col) => {
|
|
||||||
if (col.colIndex === 0 && col.rowIndex === 0) {
|
|
||||||
col.label = indexLabel
|
|
||||||
col.value = indexLabel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// tooltip
|
// tooltip
|
||||||
this.configTooltip(chart, s2Options)
|
this.configTooltip(chart, s2Options)
|
||||||
// 隐藏表头,保留顶部的分割线, 禁用表头横向 resize
|
// 隐藏表头,保留顶部的分割线, 禁用表头横向 resize
|
||||||
@ -193,13 +181,12 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
|||||||
chart.container = container
|
chart.container = container
|
||||||
this.configHeaderInteraction(chart, s2Options)
|
this.configHeaderInteraction(chart, s2Options)
|
||||||
}
|
}
|
||||||
|
// 配置总计和序号列
|
||||||
// 总计
|
this.configSummaryRowAndIndex(chart, pageInfo, s2Options, s2DataConfig)
|
||||||
configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary)
|
|
||||||
// 开始渲染
|
// 开始渲染
|
||||||
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
const newChart = new TableSheet(containerDom, s2DataConfig, s2Options)
|
||||||
// 总计紧贴在单元格后面
|
// 总计紧贴在单元格后面
|
||||||
summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
|
this.summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary)
|
||||||
// 自适应铺满
|
// 自适应铺满
|
||||||
if (basicStyle.tableColumnMode === 'adapt') {
|
if (basicStyle.tableColumnMode === 'adapt') {
|
||||||
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => {
|
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => {
|
||||||
@ -281,19 +268,86 @@ export class TableNormal extends S2ChartView<TableSheet> {
|
|||||||
if (show) {
|
if (show) {
|
||||||
newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||||
newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta))
|
||||||
|
// touch
|
||||||
|
this.configTouchEvent(newChart, drawOption, meta)
|
||||||
}
|
}
|
||||||
// header resize
|
// header resize
|
||||||
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev))
|
newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev))
|
||||||
// right click
|
// right click
|
||||||
newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta))
|
newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta))
|
||||||
// touch
|
|
||||||
this.configTouchEvent(newChart, drawOption, meta)
|
|
||||||
// theme
|
// theme
|
||||||
const customTheme = this.configTheme(chart)
|
const customTheme = this.configTheme(chart)
|
||||||
newChart.setThemeCfg({ theme: customTheme })
|
newChart.setThemeCfg({ theme: customTheme })
|
||||||
|
|
||||||
return newChart
|
return newChart
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected configSummaryRowAndIndex(
|
||||||
|
chart: Chart,
|
||||||
|
pageInfo: PageInfo,
|
||||||
|
s2Options: S2Options,
|
||||||
|
s2DataConfig: S2DataConfig
|
||||||
|
) {
|
||||||
|
const { tableHeader, basicStyle } = parseJson(chart.customAttr)
|
||||||
|
// 开启序号之后,第一列就是序号列,修改 label 即可
|
||||||
|
if (s2Options.showSeriesNumber) {
|
||||||
|
let indexLabel = tableHeader.indexLabel
|
||||||
|
if (!indexLabel) {
|
||||||
|
indexLabel = ''
|
||||||
|
}
|
||||||
|
s2Options.layoutCoordinate = (_, __, col) => {
|
||||||
|
if (col.colIndex === 0 && col.rowIndex === 0) {
|
||||||
|
col.label = indexLabel
|
||||||
|
col.value = indexLabel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { showSummary, summaryLabel } = basicStyle
|
||||||
|
const data = s2DataConfig.data
|
||||||
|
const { xAxis, yAxis } = chart
|
||||||
|
if (showSummary && data?.length) {
|
||||||
|
// 设置汇总行高度和表头一致
|
||||||
|
const heightByField = {}
|
||||||
|
heightByField[data.length] = tableHeader.tableTitleHeight
|
||||||
|
s2Options.style.rowCfg = { heightByField }
|
||||||
|
// 计算汇总加入到数据里,冻结最后一行
|
||||||
|
s2Options.frozenTrailingRowCount = 1
|
||||||
|
const summaryObj = getSummaryRow(data, yAxis, basicStyle.seriesSummary) as any
|
||||||
|
data.push(summaryObj)
|
||||||
|
}
|
||||||
|
s2Options.dataCell = viewMeta => {
|
||||||
|
// 总计行处理
|
||||||
|
if (showSummary && viewMeta.rowIndex === data.length - 1) {
|
||||||
|
if (viewMeta.colIndex === 0) {
|
||||||
|
if (tableHeader.showIndex || xAxis?.length) {
|
||||||
|
viewMeta.fieldValue = summaryLabel ?? t('chart.total_show')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new SummaryCell(viewMeta, viewMeta?.spreadsheet)
|
||||||
|
}
|
||||||
|
if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) {
|
||||||
|
viewMeta.fieldValue = pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1
|
||||||
|
}
|
||||||
|
return new CustomDataCell(viewMeta, viewMeta?.spreadsheet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected summaryRowStyle(newChart, newData, tableCell, tableHeader, showSummary) {
|
||||||
|
if (!showSummary || !newData.length) return
|
||||||
|
newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
|
||||||
|
const showHeader = tableHeader.showTableHeader === true
|
||||||
|
// 不显示表头时,减少一个表头的高度
|
||||||
|
const headerAndSummaryHeight = showHeader ? 2 : 1
|
||||||
|
const totalHeight =
|
||||||
|
tableHeader.tableTitleHeight * headerAndSummaryHeight +
|
||||||
|
tableCell.tableItemHeight * (newData.length - 1)
|
||||||
|
if (totalHeight < newChart.container.cfg.height) {
|
||||||
|
newChart.options.height =
|
||||||
|
totalHeight < newChart.container.cfg.height - 8 ? totalHeight + 8 : totalHeight
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super('table-normal', [])
|
super('table-normal', [])
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,8 @@ import {
|
|||||||
TotalStatus,
|
TotalStatus,
|
||||||
Aggregation,
|
Aggregation,
|
||||||
S2DataConfig,
|
S2DataConfig,
|
||||||
MergedCell
|
MergedCell,
|
||||||
|
LayoutResult
|
||||||
} from '@antv/s2'
|
} from '@antv/s2'
|
||||||
import { formatterItem, valueFormatter } from '../../../formatter'
|
import { formatterItem, valueFormatter } from '../../../formatter'
|
||||||
import { hexColorToRGBA, isAlphaColor, parseJson } from '../../../util'
|
import { hexColorToRGBA, isAlphaColor, parseJson } from '../../../util'
|
||||||
@ -91,7 +92,8 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
'showColTooltip',
|
'showColTooltip',
|
||||||
'showRowTooltip',
|
'showRowTooltip',
|
||||||
'showHorizonBorder',
|
'showHorizonBorder',
|
||||||
'showVerticalBorder'
|
'showVerticalBorder',
|
||||||
|
'rowHeaderFreeze'
|
||||||
],
|
],
|
||||||
'table-total-selector': ['row', 'col'],
|
'table-total-selector': ['row', 'col'],
|
||||||
'basic-style-selector': [
|
'basic-style-selector': [
|
||||||
@ -100,7 +102,9 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
'tableScrollBarColor',
|
'tableScrollBarColor',
|
||||||
'alpha',
|
'alpha',
|
||||||
'tableLayoutMode',
|
'tableLayoutMode',
|
||||||
'showHoverStyle'
|
'showHoverStyle',
|
||||||
|
'quotaPosition',
|
||||||
|
'quotaColLabel'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
axis: AxisType[] = ['xAxis', 'xAxisExt', 'yAxis', 'filter']
|
axis: AxisType[] = ['xAxis', 'xAxisExt', 'yAxis', 'filter']
|
||||||
@ -162,7 +166,7 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if (![2, 3].includes(f.deType) || !isNumber(value)) {
|
if (![2, 3, 4].includes(f.deType) || !isNumber(value)) {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if (f.formatterCfg) {
|
if (f.formatterCfg) {
|
||||||
@ -175,7 +179,7 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// total config
|
// total config
|
||||||
const { basicStyle, tooltip, tableTotal } = parseJson(chart.customAttr)
|
const { basicStyle, tooltip, tableTotal, tableHeader } = parseJson(chart.customAttr)
|
||||||
if (!tableTotal.row.subTotalsDimensionsNew || tableTotal.row.subTotalsDimensions == undefined) {
|
if (!tableTotal.row.subTotalsDimensionsNew || tableTotal.row.subTotalsDimensions == undefined) {
|
||||||
tableTotal.row.subTotalsDimensions = r
|
tableTotal.row.subTotalsDimensions = r
|
||||||
}
|
}
|
||||||
@ -183,6 +187,7 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
|
|
||||||
// 解析合计、小计排序
|
// 解析合计、小计排序
|
||||||
const sortParams = []
|
const sortParams = []
|
||||||
|
let rowTotalSort = false
|
||||||
if (
|
if (
|
||||||
tableTotal.row.totalSort &&
|
tableTotal.row.totalSort &&
|
||||||
tableTotal.row.totalSort !== 'none' &&
|
tableTotal.row.totalSort !== 'none' &&
|
||||||
@ -190,8 +195,9 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
tableTotal.row.showGrandTotals &&
|
tableTotal.row.showGrandTotals &&
|
||||||
v.indexOf(tableTotal.row.totalSortField) > -1
|
v.indexOf(tableTotal.row.totalSortField) > -1
|
||||||
) {
|
) {
|
||||||
|
c.forEach(i => {
|
||||||
const sort = {
|
const sort = {
|
||||||
sortFieldId: c[0],
|
sortFieldId: i,
|
||||||
sortMethod: tableTotal.row.totalSort.toUpperCase(),
|
sortMethod: tableTotal.row.totalSort.toUpperCase(),
|
||||||
sortByMeasure: TOTAL_VALUE,
|
sortByMeasure: TOTAL_VALUE,
|
||||||
query: {
|
query: {
|
||||||
@ -199,7 +205,10 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sortParams.push(sort)
|
sortParams.push(sort)
|
||||||
|
})
|
||||||
|
rowTotalSort = true
|
||||||
}
|
}
|
||||||
|
let colTotalSort = false
|
||||||
if (
|
if (
|
||||||
tableTotal.col.totalSort &&
|
tableTotal.col.totalSort &&
|
||||||
tableTotal.col.totalSort !== 'none' &&
|
tableTotal.col.totalSort !== 'none' &&
|
||||||
@ -207,8 +216,9 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
tableTotal.col.showGrandTotals &&
|
tableTotal.col.showGrandTotals &&
|
||||||
v.indexOf(tableTotal.col.totalSortField) > -1
|
v.indexOf(tableTotal.col.totalSortField) > -1
|
||||||
) {
|
) {
|
||||||
|
r.forEach(i => {
|
||||||
const sort = {
|
const sort = {
|
||||||
sortFieldId: r[0],
|
sortFieldId: i,
|
||||||
sortMethod: tableTotal.col.totalSort.toUpperCase(),
|
sortMethod: tableTotal.col.totalSort.toUpperCase(),
|
||||||
sortByMeasure: TOTAL_VALUE,
|
sortByMeasure: TOTAL_VALUE,
|
||||||
query: {
|
query: {
|
||||||
@ -216,6 +226,8 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sortParams.push(sort)
|
sortParams.push(sort)
|
||||||
|
})
|
||||||
|
colTotalSort = true
|
||||||
}
|
}
|
||||||
//列维度为空,行排序按照指标列来排序,取第一个有排序设置的指标
|
//列维度为空,行排序按照指标列来排序,取第一个有排序设置的指标
|
||||||
if (!columnFields?.length) {
|
if (!columnFields?.length) {
|
||||||
@ -244,9 +256,23 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
col: chart.xAxisExt,
|
col: chart.xAxisExt,
|
||||||
quota: chart.yAxis
|
quota: chart.yAxis
|
||||||
}
|
}
|
||||||
//树形模式下,列维度为空,行小计会变成列总计,特殊处理下
|
// 沒有列维度需要特殊处理
|
||||||
if (basicStyle.tableLayoutMode === 'tree' && !chart.xAxisExt?.length) {
|
if (!chart.xAxisExt?.length) {
|
||||||
|
//树形模式下,列维度为空,行小计的配置会变成列总计
|
||||||
|
if (basicStyle.tableLayoutMode === 'tree') {
|
||||||
tableTotal.col.calcTotals = tableTotal.row.calcSubTotals
|
tableTotal.col.calcTotals = tableTotal.row.calcSubTotals
|
||||||
|
if (!tableTotal.col.calcTotals.cfg?.length) {
|
||||||
|
tableTotal.col.calcTotals.cfg = chart.yAxis.map(y => {
|
||||||
|
return {
|
||||||
|
dataeaseName: y.dataeaseName,
|
||||||
|
aggregation: 'SUM'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 列总计设置为空
|
||||||
|
tableTotal.col.calcTotals.calcFunc = () => '-'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
totals.forEach(total => {
|
totals.forEach(total => {
|
||||||
if (total.cfg?.length) {
|
if (total.cfg?.length) {
|
||||||
@ -262,12 +288,93 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
})
|
})
|
||||||
// 空值处理
|
// 空值处理
|
||||||
const newData = this.configEmptyDataStrategy(chart)
|
const newData = this.configEmptyDataStrategy(chart)
|
||||||
|
// 行列维度排序
|
||||||
|
if (!rowTotalSort) {
|
||||||
|
c?.forEach((f, i) => {
|
||||||
|
if (valueFieldMap[f]?.sort === 'none') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const sort = {
|
||||||
|
sortFieldId: f
|
||||||
|
}
|
||||||
|
const sortMethod = valueFieldMap[f]?.sort?.toUpperCase()
|
||||||
|
if (sortMethod === 'CUSTOM_SORT') {
|
||||||
|
sort.sortBy = valueFieldMap[f].customSort
|
||||||
|
} else {
|
||||||
|
if (i === 0) {
|
||||||
|
sort.sortMethod = sortMethod
|
||||||
|
} else {
|
||||||
|
const fieldValues = newData.map(item => item[f])
|
||||||
|
const uniqueValues = [...new Set(fieldValues)]
|
||||||
|
|
||||||
|
// 根据配置动态决定排序顺序
|
||||||
|
uniqueValues.sort((a, b) => {
|
||||||
|
if ([2, 3, 4].includes(valueFieldMap[f]?.deType)) {
|
||||||
|
return sortMethod === 'ASC' ? a - b : b - a
|
||||||
|
}
|
||||||
|
if (!a && !b) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if (!a) {
|
||||||
|
return sortMethod === 'ASC' ? -1 : 1
|
||||||
|
}
|
||||||
|
if (!b) {
|
||||||
|
return sortMethod === 'ASC' ? 1 : -1
|
||||||
|
}
|
||||||
|
return sortMethod === 'ASC' ? a.localeCompare(b) : b.localeCompare(a)
|
||||||
|
})
|
||||||
|
sort.sortBy = uniqueValues
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortParams.push(sort)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!colTotalSort) {
|
||||||
|
r?.forEach((f, i) => {
|
||||||
|
if (valueFieldMap[f]?.sort === 'none') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const sort = {
|
||||||
|
sortFieldId: f
|
||||||
|
}
|
||||||
|
const sortMethod = valueFieldMap[f]?.sort?.toUpperCase()
|
||||||
|
if (sortMethod === 'CUSTOM_SORT') {
|
||||||
|
sort.sortBy = valueFieldMap[f].customSort
|
||||||
|
} else {
|
||||||
|
if (i === 0) {
|
||||||
|
sort.sortMethod = sortMethod
|
||||||
|
} else {
|
||||||
|
const fieldValues = newData.map(item => item[f])
|
||||||
|
const uniqueValues = [...new Set(fieldValues)]
|
||||||
|
// 根据配置动态决定排序顺序
|
||||||
|
uniqueValues.sort((a, b) => {
|
||||||
|
if ([2, 3, 4].includes(valueFieldMap[f]?.deType)) {
|
||||||
|
return sortMethod === 'ASC' ? a - b : b - a
|
||||||
|
}
|
||||||
|
if (!a && !b) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if (!a) {
|
||||||
|
return sortMethod === 'ASC' ? -1 : 1
|
||||||
|
}
|
||||||
|
if (!b) {
|
||||||
|
return sortMethod === 'ASC' ? 1 : -1
|
||||||
|
}
|
||||||
|
return sortMethod === 'ASC' ? a.localeCompare(b) : b.localeCompare(a)
|
||||||
|
})
|
||||||
|
sort.sortBy = uniqueValues
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortParams.push(sort)
|
||||||
|
})
|
||||||
|
}
|
||||||
// data config
|
// data config
|
||||||
const s2DataConfig: S2DataConfig = {
|
const s2DataConfig: S2DataConfig = {
|
||||||
fields: {
|
fields: {
|
||||||
rows: r,
|
rows: r,
|
||||||
columns: c,
|
columns: c,
|
||||||
values: v
|
values: v,
|
||||||
|
valueInCols: !(basicStyle.quotaPosition === 'row')
|
||||||
},
|
},
|
||||||
meta: meta,
|
meta: meta,
|
||||||
data: newData,
|
data: newData,
|
||||||
@ -277,6 +384,7 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
width: containerDom.offsetWidth,
|
width: containerDom.offsetWidth,
|
||||||
height: containerDom.offsetHeight,
|
height: containerDom.offsetHeight,
|
||||||
totals: tableTotal as Totals,
|
totals: tableTotal as Totals,
|
||||||
|
cornerExtraFieldText: basicStyle.quotaColLabel ?? t('dataset.value'),
|
||||||
conditions: this.configConditions(chart),
|
conditions: this.configConditions(chart),
|
||||||
tooltip: {
|
tooltip: {
|
||||||
getContainer: () => containerDom
|
getContainer: () => containerDom
|
||||||
@ -288,21 +396,204 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
},
|
},
|
||||||
dataCell: meta => {
|
dataCell: meta => {
|
||||||
return new CustomDataCell(meta, meta.spreadsheet)
|
return new CustomDataCell(meta, meta.spreadsheet)
|
||||||
}
|
},
|
||||||
|
frozenRowHeader: !(tableHeader.rowHeaderFreeze === false)
|
||||||
}
|
}
|
||||||
// options
|
// options
|
||||||
s2Options.style = this.configStyle(chart, s2DataConfig)
|
s2Options.style = this.configStyle(chart, s2DataConfig)
|
||||||
|
// 默认展开层级
|
||||||
|
if (basicStyle.tableLayoutMode === 'tree') {
|
||||||
|
const { defaultExpandLevel } = basicStyle
|
||||||
|
if (isNumber(defaultExpandLevel)) {
|
||||||
|
if (defaultExpandLevel >= chart.xAxis.length) {
|
||||||
|
s2Options.style.rowExpandDepth = defaultExpandLevel
|
||||||
|
} else {
|
||||||
|
s2Options.style.rowExpandDepth = defaultExpandLevel - 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defaultExpandLevel === 'all') {
|
||||||
|
s2Options.style.rowExpandDepth = chart.xAxis.length
|
||||||
|
}
|
||||||
|
if (!defaultExpandLevel) {
|
||||||
s2Options.style.hierarchyCollapse = true
|
s2Options.style.hierarchyCollapse = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 列汇总别名
|
||||||
|
if (!(basicStyle.quotaPosition === 'row' && basicStyle.tableLayoutMode === 'tree')) {
|
||||||
|
if (
|
||||||
|
basicStyle.quotaPosition !== 'row' &&
|
||||||
|
chart.xAxisExt?.length &&
|
||||||
|
chart.yAxis?.length > 1 &&
|
||||||
|
tableTotal.col.showGrandTotals &&
|
||||||
|
tableTotal.col.calcTotals?.cfg?.length
|
||||||
|
) {
|
||||||
|
const colTotalCfgMap = tableTotal.col.calcTotals.cfg.reduce((p, n) => {
|
||||||
|
p[n.dataeaseName] = n
|
||||||
|
return p
|
||||||
|
}, {})
|
||||||
|
s2Options.layoutCoordinate = (_, __, col) => {
|
||||||
|
if (col?.isGrandTotals) {
|
||||||
|
if (colTotalCfgMap[col.value]?.label) {
|
||||||
|
col.label = colTotalCfgMap[col.value].label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
basicStyle.quotaPosition === 'row' &&
|
||||||
|
chart.xAxisExt?.length &&
|
||||||
|
chart.yAxis?.length > 1 &&
|
||||||
|
tableTotal.row.showGrandTotals &&
|
||||||
|
tableTotal.row.calcTotals?.cfg?.length
|
||||||
|
) {
|
||||||
|
const rowTotalCfgMap = tableTotal.row.calcTotals.cfg.reduce((p, n) => {
|
||||||
|
p[n.dataeaseName] = n
|
||||||
|
return p
|
||||||
|
}, {})
|
||||||
|
// eslint-disable-next-line
|
||||||
|
s2Options.layoutCoordinate = (_, row, __) => {
|
||||||
|
if (row?.isGrandTotals) {
|
||||||
|
if (rowTotalCfgMap[row.value]?.label) {
|
||||||
|
row.label = rowTotalCfgMap[row.value].label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// tooltip
|
// tooltip
|
||||||
this.configTooltip(chart, s2Options)
|
this.configTooltip(chart, s2Options)
|
||||||
// 开始渲染
|
// 开始渲染
|
||||||
const s2 = new PivotSheet(containerDom, s2DataConfig, s2Options as unknown as S2Options)
|
const s2 = new PivotSheet(containerDom, s2DataConfig, s2Options as unknown as S2Options)
|
||||||
|
// 自适应铺满
|
||||||
|
if (basicStyle.tableColumnMode === 'adapt') {
|
||||||
|
s2.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => {
|
||||||
|
s2.store.set('lastLayoutResult', s2.facet.layoutResult)
|
||||||
|
})
|
||||||
|
// 平铺模式行头resize
|
||||||
|
s2.on(S2Event.LAYOUT_RESIZE_ROW_WIDTH, () => {
|
||||||
|
s2.store.set('lastLayoutResult', s2.facet.layoutResult)
|
||||||
|
})
|
||||||
|
// 树形模式行头resize
|
||||||
|
s2.on(S2Event.LAYOUT_RESIZE_TREE_WIDTH, () => {
|
||||||
|
s2.store.set('lastLayoutResult', s2.facet.layoutResult)
|
||||||
|
})
|
||||||
|
s2.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => {
|
||||||
|
const lastLayoutResult = s2.store.get('lastLayoutResult') as LayoutResult
|
||||||
|
if (lastLayoutResult) {
|
||||||
|
// 拖动 col 表头 resize
|
||||||
|
const colWidthByFieldValue = s2.options.style?.colCfg?.widthByFieldValue
|
||||||
|
// 平铺模式拖动 row 表头 resize
|
||||||
|
const rowWidthByField = s2.options.style?.rowCfg?.widthByField
|
||||||
|
// 树形模式拖动 row 表头 resize
|
||||||
|
const treeRowWidth =
|
||||||
|
s2.options.style?.treeRowsWidth || lastLayoutResult.rowsHierarchy.width
|
||||||
|
const colWidthMap =
|
||||||
|
lastLayoutResult.colLeafNodes.reduce((p, n) => {
|
||||||
|
p[n.id] = colWidthByFieldValue?.[n.value] ?? n.width
|
||||||
|
return p
|
||||||
|
}, {}) || {}
|
||||||
|
const totalColWidth = ev.colLeafNodes.reduce((p, n) => {
|
||||||
|
n.width = colWidthMap[n.id] || n.width
|
||||||
|
n.x = p
|
||||||
|
return p + n.width
|
||||||
|
}, 0)
|
||||||
|
ev.colNodes.forEach(n => {
|
||||||
|
if (n.isLeaf) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n.width = this.getColWidth(n)
|
||||||
|
n.x = this.getLeftChild(n).x
|
||||||
|
})
|
||||||
|
if (basicStyle.tableLayoutMode === 'tree') {
|
||||||
|
ev.rowNodes.forEach(n => {
|
||||||
|
n.width = treeRowWidth
|
||||||
|
})
|
||||||
|
ev.rowsHierarchy.width = treeRowWidth
|
||||||
|
ev.colsHierarchy.width = totalColWidth
|
||||||
|
} else {
|
||||||
|
const rowWidthMap =
|
||||||
|
lastLayoutResult.rowNodes.reduce((p, n) => {
|
||||||
|
p[n.id] = rowWidthByField?.[n.field] ?? n.width
|
||||||
|
return p
|
||||||
|
}, {}) || {}
|
||||||
|
ev.rowNodes.forEach(n => {
|
||||||
|
n.x = 0
|
||||||
|
n.width = rowWidthMap[n.id] || n.width
|
||||||
|
let tmp = n
|
||||||
|
while (tmp.parent.id !== 'root') {
|
||||||
|
n.x += tmp.parent.width
|
||||||
|
tmp = tmp.parent
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const totlaRowWidth = ev.rowsHierarchy.sampleNodesForAllLevels.reduce((p, n) => {
|
||||||
|
return p + n.width
|
||||||
|
}, 0)
|
||||||
|
const maxRowLevel = ev.rowsHierarchy.maxLevel
|
||||||
|
ev.rowNodes.forEach(n => {
|
||||||
|
// 总计和中间层级的小计需要重新计算宽度
|
||||||
|
if (n.isTotalRoot || (n.isSubTotals && n.level < maxRowLevel)) {
|
||||||
|
let width = 0
|
||||||
|
for (let i = n.level; i <= maxRowLevel; i++) {
|
||||||
|
width += ev.rowsHierarchy.sampleNodesForAllLevels[i].width
|
||||||
|
}
|
||||||
|
n.width = width
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ev.rowsHierarchy.width = totlaRowWidth
|
||||||
|
ev.colsHierarchy.width = totalColWidth
|
||||||
|
}
|
||||||
|
s2.store.set('lastLayoutResult', undefined)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const containerWidth = containerDom.getBoundingClientRect().width
|
||||||
|
const scale = containerWidth / (ev.colsHierarchy.width + ev.rowsHierarchy.width)
|
||||||
|
if (scale <= 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const totalRowWidth = Math.round(ev.rowsHierarchy.width * scale)
|
||||||
|
ev.rowNodes.forEach(n => {
|
||||||
|
n.width = Math.round(n.width * scale)
|
||||||
|
})
|
||||||
|
if (basicStyle.tableLayoutMode !== 'tree') {
|
||||||
|
ev.rowNodes.forEach(n => {
|
||||||
|
n.x = 0
|
||||||
|
let tmp = n
|
||||||
|
while (tmp.parent.id !== 'root') {
|
||||||
|
n.x += tmp.parent.width
|
||||||
|
tmp = tmp.parent
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let totalColWidth = ev.colLeafNodes.reduce((p, n) => {
|
||||||
|
n.width = Math.round(n.width * scale)
|
||||||
|
n.x = p
|
||||||
|
return p + n.width
|
||||||
|
}, 0)
|
||||||
|
ev.colNodes.forEach(n => {
|
||||||
|
if (n.isLeaf) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n.width = this.getColWidth(n)
|
||||||
|
n.x = this.getLeftChild(n).x
|
||||||
|
})
|
||||||
|
const totalWidth = totalColWidth + totalRowWidth
|
||||||
|
if (totalWidth > containerWidth) {
|
||||||
|
// 从最后一列减掉
|
||||||
|
ev.colLeafNodes[ev.colLeafNodes.length - 1].width -= totalWidth - containerWidth
|
||||||
|
totalColWidth = totalColWidth - (totalWidth - containerWidth)
|
||||||
|
}
|
||||||
|
ev.colsHierarchy.width = totalColWidth
|
||||||
|
ev.rowsHierarchy.width = totalRowWidth
|
||||||
|
})
|
||||||
|
}
|
||||||
// tooltip
|
// tooltip
|
||||||
const { show } = tooltip
|
const { show } = tooltip
|
||||||
if (show) {
|
if (show) {
|
||||||
s2.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(s2, event, meta))
|
s2.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(s2, event, meta))
|
||||||
s2.on(S2Event.ROW_CELL_HOVER, event => this.showTooltip(s2, event, meta))
|
s2.on(S2Event.ROW_CELL_HOVER, event => this.showTooltip(s2, event, meta))
|
||||||
s2.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(s2, event, meta))
|
s2.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(s2, event, meta))
|
||||||
|
// touch
|
||||||
|
this.configTouchEvent(s2, drawOption, meta)
|
||||||
}
|
}
|
||||||
// empty data tip
|
// empty data tip
|
||||||
configEmptyDataStyle(s2, newData)
|
configEmptyDataStyle(s2, newData)
|
||||||
@ -312,14 +603,29 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
s2.on(S2Event.COL_CELL_CLICK, ev => this.headerCellClickAction(chart, ev, s2, action))
|
s2.on(S2Event.COL_CELL_CLICK, ev => this.headerCellClickAction(chart, ev, s2, action))
|
||||||
// right click
|
// right click
|
||||||
s2.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(s2, event, meta))
|
s2.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(s2, event, meta))
|
||||||
// touch
|
|
||||||
this.configTouchEvent(s2, drawOption, meta)
|
|
||||||
// theme
|
// theme
|
||||||
const customTheme = this.configTheme(chart)
|
const customTheme = this.configTheme(chart)
|
||||||
s2.setThemeCfg({ theme: customTheme })
|
s2.setThemeCfg({ theme: customTheme })
|
||||||
|
|
||||||
return s2
|
return s2
|
||||||
}
|
}
|
||||||
|
private getColWidth(node) {
|
||||||
|
let width = 0
|
||||||
|
if (node.children?.length) {
|
||||||
|
node.children.forEach(child => {
|
||||||
|
width += this.getColWidth(child)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
width = node.width
|
||||||
|
}
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
private getLeftChild(node) {
|
||||||
|
if (!node.children?.length) {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
return this.getLeftChild(node.children[0])
|
||||||
|
}
|
||||||
private dataCellClickAction(chart: Chart, ev, s2Instance: PivotSheet, callback) {
|
private dataCellClickAction(chart: Chart, ev, s2Instance: PivotSheet, callback) {
|
||||||
const cell = s2Instance.getCell(ev.target)
|
const cell = s2Instance.getCell(ev.target)
|
||||||
const meta = cell.getMeta()
|
const meta = cell.getMeta()
|
||||||
@ -522,7 +828,7 @@ export class TablePivot extends S2ChartView<PivotSheet> {
|
|||||||
}
|
}
|
||||||
function customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, customCalc) {
|
function customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, customCalc) {
|
||||||
if (!data?.length || !query[EXTRA_FIELD]) {
|
if (!data?.length || !query[EXTRA_FIELD]) {
|
||||||
return 0
|
return '-'
|
||||||
}
|
}
|
||||||
const aggregation = totalCfgMap[query[EXTRA_FIELD]]?.aggregation || 'SUM'
|
const aggregation = totalCfgMap[query[EXTRA_FIELD]]?.aggregation || 'SUM'
|
||||||
switch (aggregation) {
|
switch (aggregation) {
|
||||||
@ -549,10 +855,13 @@ function customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, custom
|
|||||||
})
|
})
|
||||||
return result?.[query[EXTRA_FIELD]]
|
return result?.[query[EXTRA_FIELD]]
|
||||||
}
|
}
|
||||||
|
case 'NONE': {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
case 'CUSTOM': {
|
case 'CUSTOM': {
|
||||||
const val = getCustomCalcResult(query, axisMap, chart, status, customCalc || {})
|
const val = getCustomCalcResult(query, axisMap, chart, status, customCalc || {})
|
||||||
if (val === '') {
|
if (val === '' || val === undefined) {
|
||||||
return val
|
return '-'
|
||||||
}
|
}
|
||||||
return parseFloat(val)
|
return parseFloat(val)
|
||||||
}
|
}
|
||||||
@ -593,11 +902,17 @@ function getTreeCustomCalcResult(query, axisMap, status: TotalStatus, customCalc
|
|||||||
// 列小计
|
// 列小计
|
||||||
if (status.isColSubTotal && !status.isRowTotal && !status.isRowSubTotal) {
|
if (status.isColSubTotal && !status.isRowTotal && !status.isRowSubTotal) {
|
||||||
const { colSubTotal } = customCalc
|
const { colSubTotal } = customCalc
|
||||||
const subLevel = getSubLevel(query, col)
|
const subColLevel = getSubLevel(query, col)
|
||||||
|
const subRowLevel = getSubLevel(query, row)
|
||||||
const rowPath = getTreePath(query, row)
|
const rowPath = getTreePath(query, row)
|
||||||
const colPath = getTreePath(query, col)
|
const colPath = getTreePath(query, col)
|
||||||
const path = [...rowPath, ...colPath]
|
const path = [...rowPath, ...colPath]
|
||||||
const data = colSubTotal?.[subLevel]?.data
|
let data = colSubTotal?.[subColLevel]?.data
|
||||||
|
// 列小计里面的行小计
|
||||||
|
if (rowPath.length < row.length) {
|
||||||
|
const { rowSubInColSub } = customCalc
|
||||||
|
data = rowSubInColSub?.[subRowLevel]?.[subColLevel]?.data
|
||||||
|
}
|
||||||
let val
|
let val
|
||||||
if (path.length && data) {
|
if (path.length && data) {
|
||||||
path.push(quotaField)
|
path.push(quotaField)
|
||||||
@ -647,7 +962,7 @@ function getTreeCustomCalcResult(query, axisMap, status: TotalStatus, customCalc
|
|||||||
if (status.isRowTotal && status.isColSubTotal) {
|
if (status.isRowTotal && status.isColSubTotal) {
|
||||||
const { colSubInRowTotal } = customCalc
|
const { colSubInRowTotal } = customCalc
|
||||||
const colLevel = getSubLevel(query, col)
|
const colLevel = getSubLevel(query, col)
|
||||||
const { data } = colSubInRowTotal?.[colLevel]
|
const data = colSubInRowTotal?.[colLevel]?.data
|
||||||
const colPath = getTreePath(query, col)
|
const colPath = getTreePath(query, col)
|
||||||
let val
|
let val
|
||||||
if (colPath.length && colSubInRowTotal) {
|
if (colPath.length && colSubInRowTotal) {
|
||||||
@ -669,23 +984,7 @@ function getTreeCustomCalcResult(query, axisMap, status: TotalStatus, customCalc
|
|||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
// 列小计里面的行小计
|
return '-'
|
||||||
if (status.isColSubTotal && status.isRowSubTotal) {
|
|
||||||
const { rowSubInColSub } = customCalc
|
|
||||||
const rowSubLevel = getSubLevel(query, row)
|
|
||||||
const colSubLevel = getSubLevel(query, col)
|
|
||||||
const data = rowSubInColSub?.[rowSubLevel]?.[colSubLevel]?.data
|
|
||||||
const rowPath = getTreePath(query, row)
|
|
||||||
const colPath = getTreePath(query, col)
|
|
||||||
const path = [...rowPath, ...colPath]
|
|
||||||
let val
|
|
||||||
if (path.length && rowSubInColSub) {
|
|
||||||
path.push(quotaField)
|
|
||||||
val = get(data, path)
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return NaN
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGridCustomCalcResult(query, axisMap, status: TotalStatus, customCalc) {
|
function getGridCustomCalcResult(query, axisMap, status: TotalStatus, customCalc) {
|
||||||
@ -759,7 +1058,7 @@ function getGridCustomCalcResult(query, axisMap, status: TotalStatus, customCalc
|
|||||||
if (status.isRowTotal && status.isColSubTotal) {
|
if (status.isRowTotal && status.isColSubTotal) {
|
||||||
const { colSubInRowTotal } = customCalc
|
const { colSubInRowTotal } = customCalc
|
||||||
const colLevel = getSubLevel(query, col)
|
const colLevel = getSubLevel(query, col)
|
||||||
const { data } = colSubInRowTotal?.[colLevel]
|
const data = colSubInRowTotal?.[colLevel]?.data
|
||||||
const colPath = getTreePath(query, col)
|
const colPath = getTreePath(query, col)
|
||||||
let val
|
let val
|
||||||
if (colPath.length && colSubInRowTotal) {
|
if (colPath.length && colSubInRowTotal) {
|
||||||
|
@ -33,10 +33,23 @@ import { PositionType } from '@antv/l7-core'
|
|||||||
import { centroid } from '@turf/centroid'
|
import { centroid } from '@turf/centroid'
|
||||||
import type { Plot } from '@antv/g2plot'
|
import type { Plot } from '@antv/g2plot'
|
||||||
import type { PickOptions } from '@antv/g2plot/lib/core/plot'
|
import type { PickOptions } from '@antv/g2plot/lib/core/plot'
|
||||||
import { defaults } from 'lodash-es'
|
import { defaults, find } from 'lodash-es'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
const { t: tI18n } = useI18n()
|
|
||||||
import { isMobile } from '@/utils/utils'
|
import { isMobile } from '@/utils/utils'
|
||||||
|
import { GaodeMap, TMap, TencentMap } from '@antv/l7-maps'
|
||||||
|
import {
|
||||||
|
gaodeMapStyleOptions,
|
||||||
|
qqMapStyleOptions,
|
||||||
|
tdtMapStyleOptions
|
||||||
|
} from '@/views/chart/components/js/panel/charts/map/common'
|
||||||
|
import ChartCarouselTooltip, {
|
||||||
|
isPie,
|
||||||
|
isColumn,
|
||||||
|
isMix,
|
||||||
|
isSupport
|
||||||
|
} from '@/views/chart/components/js/g2plot_tooltip_carousel'
|
||||||
|
|
||||||
|
const { t: tI18n } = useI18n()
|
||||||
|
|
||||||
export function getPadding(chart: Chart): number[] {
|
export function getPadding(chart: Chart): number[] {
|
||||||
if (chart.drill) {
|
if (chart.drill) {
|
||||||
@ -137,14 +150,22 @@ export function getTheme(chart: Chart) {
|
|||||||
},
|
},
|
||||||
'g2-tooltip-list-item': {
|
'g2-tooltip-list-item': {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
'align-items': 'center'
|
'align-items': 'flex-start',
|
||||||
|
'justify-content': 'space-between',
|
||||||
|
'line-height': tooltipFontsize + 'px'
|
||||||
},
|
},
|
||||||
'g2-tooltip-name': {
|
'g2-tooltip-name': {
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
'line-height': tooltipFontsize + 'px',
|
'line-height': tooltipFontsize + 'px'
|
||||||
flex: 1
|
},
|
||||||
|
'g2-tooltip-value': {
|
||||||
|
flex: 1,
|
||||||
|
display: 'inline-block',
|
||||||
|
'text-align': 'end',
|
||||||
|
'line-height': tooltipFontsize + 'px'
|
||||||
},
|
},
|
||||||
'g2-tooltip-marker': {
|
'g2-tooltip-marker': {
|
||||||
|
'margin-top': (tooltipFontsize - 8) / 2 + 'px',
|
||||||
'min-width': '8px',
|
'min-width': '8px',
|
||||||
'min-height': '8px'
|
'min-height': '8px'
|
||||||
}
|
}
|
||||||
@ -469,7 +490,8 @@ export function getXAxis(chart: Chart) {
|
|||||||
style: {
|
style: {
|
||||||
fill: a.axisLabel.color,
|
fill: a.axisLabel.color,
|
||||||
fontSize: a.axisLabel.fontSize,
|
fontSize: a.axisLabel.fontSize,
|
||||||
textAlign: textAlign
|
textAlign: textAlign,
|
||||||
|
fontFamily: chart.fontFamily
|
||||||
},
|
},
|
||||||
formatter: value => {
|
formatter: value => {
|
||||||
return chart.type === 'bidirectional-bar' && value.length > a.axisLabel.lengthLimit
|
return chart.type === 'bidirectional-bar' && value.length > a.axisLabel.lengthLimit
|
||||||
@ -574,7 +596,8 @@ export function getYAxis(chart: Chart) {
|
|||||||
fill: yAxis.axisLabel.color,
|
fill: yAxis.axisLabel.color,
|
||||||
fontSize: yAxis.axisLabel.fontSize,
|
fontSize: yAxis.axisLabel.fontSize,
|
||||||
textBaseline,
|
textBaseline,
|
||||||
textAlign
|
textAlign,
|
||||||
|
fontFamily: chart.fontFamily
|
||||||
},
|
},
|
||||||
formatter: value => {
|
formatter: value => {
|
||||||
return value.length > yAxis.axisLabel.lengthLimit
|
return value.length > yAxis.axisLabel.lengthLimit
|
||||||
@ -603,7 +626,7 @@ export function getYAxisExt(chart: Chart) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const title =
|
const title =
|
||||||
yAxis.name && yAxis.name !== ''
|
yAxis.nameShow && yAxis.name && yAxis.name !== ''
|
||||||
? {
|
? {
|
||||||
text: yAxis.name,
|
text: yAxis.name,
|
||||||
style: {
|
style: {
|
||||||
@ -629,14 +652,16 @@ export function getYAxisExt(chart: Chart) {
|
|||||||
? {
|
? {
|
||||||
style: {
|
style: {
|
||||||
stroke: axisCfg.lineStyle.color,
|
stroke: axisCfg.lineStyle.color,
|
||||||
lineWidth: axisCfg.lineStyle.width
|
lineWidth: axisCfg.lineStyle.width,
|
||||||
|
lineDash: getLineDash(axisCfg.lineStyle.style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
const tickLine = axisCfg.show
|
const tickLine = axisCfg.show
|
||||||
? {
|
? {
|
||||||
style: {
|
style: {
|
||||||
stroke: axisCfg.lineStyle.color
|
stroke: axisCfg.lineStyle.color,
|
||||||
|
lineWidth: axisCfg.lineStyle.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
@ -673,7 +698,8 @@ export function getYAxisExt(chart: Chart) {
|
|||||||
fill: yAxis.axisLabel.color,
|
fill: yAxis.axisLabel.color,
|
||||||
fontSize: yAxis.axisLabel.fontSize,
|
fontSize: yAxis.axisLabel.fontSize,
|
||||||
textBaseline,
|
textBaseline,
|
||||||
textAlign
|
textAlign,
|
||||||
|
fontFamily: chart.fontFamily
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
@ -821,10 +847,9 @@ export function getAnalyseHorizontal(chart: Chart) {
|
|||||||
const assistLineArr = senior.assistLineCfg.assistLine
|
const assistLineArr = senior.assistLineCfg.assistLine
|
||||||
if (assistLineArr?.length > 0) {
|
if (assistLineArr?.length > 0) {
|
||||||
const customStyle = parseJson(chart.customStyle)
|
const customStyle = parseJson(chart.customStyle)
|
||||||
let xAxisPosition, axisFormatterCfg
|
let axisFormatterCfg
|
||||||
if (customStyle.xAxis) {
|
if (customStyle.xAxis) {
|
||||||
const a = JSON.parse(JSON.stringify(customStyle.xAxis))
|
const a = JSON.parse(JSON.stringify(customStyle.xAxis))
|
||||||
xAxisPosition = transAxisPosition(a.position)
|
|
||||||
axisFormatterCfg = a.axisLabelFormatter
|
axisFormatterCfg = a.axisLabelFormatter
|
||||||
? a.axisLabelFormatter
|
? a.axisLabelFormatter
|
||||||
: DEFAULT_XAXIS_STYLE.axisLabelFormatter
|
: DEFAULT_XAXIS_STYLE.axisLabelFormatter
|
||||||
@ -894,7 +919,9 @@ export function getLineDash(type) {
|
|||||||
*/
|
*/
|
||||||
export function setGradientColor(rawColor: string, show = false, angle = 0, start = 0) {
|
export function setGradientColor(rawColor: string, show = false, angle = 0, start = 0) {
|
||||||
const item = rawColor.split(',')
|
const item = rawColor.split(',')
|
||||||
item.splice(3, 1, '0.3)')
|
const alpha = parseFloat(item[3].replace(')', ''))
|
||||||
|
const startAlpha = alpha * 0.3
|
||||||
|
item.splice(3, 1, `${startAlpha})`)
|
||||||
let color: string
|
let color: string
|
||||||
if (start == 0) {
|
if (start == 0) {
|
||||||
color = `l(${angle}) 0:${item.join(',')} 1:${rawColor}`
|
color = `l(${angle}) 0:${item.join(',')} 1:${rawColor}`
|
||||||
@ -993,6 +1020,9 @@ export function configL7Tooltip(chart: Chart): TooltipOptions {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
const head = originalItem.properties
|
const head = originalItem.properties
|
||||||
|
if (!head) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
const formatter = formatterMap[head.quotaList?.[0]?.id]
|
const formatter = formatterMap[head.quotaList?.[0]?.id]
|
||||||
if (!isEmpty(formatter)) {
|
if (!isEmpty(formatter)) {
|
||||||
const originValue = parseFloat(head.value as string)
|
const originValue = parseFloat(head.value as string)
|
||||||
@ -1152,6 +1182,19 @@ export class CustomZoom extends Zoom {
|
|||||||
'l7-button-control',
|
'l7-button-control',
|
||||||
container,
|
container,
|
||||||
() => {
|
() => {
|
||||||
|
if (this.mapsService.map?.deMapProvider == 'qq') {
|
||||||
|
if (this.mapsService.map.deMapAutoFit) {
|
||||||
|
this.mapsService.setZoomAndCenter(this.mapsService.map.deMapAutoZoom, [
|
||||||
|
this.mapsService.map.deMapAutoLng,
|
||||||
|
this.mapsService.map.deMapAutoLat
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
this.mapsService.setZoomAndCenter(
|
||||||
|
this.controlOption['initZoom'],
|
||||||
|
this.controlOption['center']
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (this.controlOption['bounds']) {
|
if (this.controlOption['bounds']) {
|
||||||
this.mapsService.fitBounds(this.controlOption['bounds'], { animate: true })
|
this.mapsService.fitBounds(this.controlOption['bounds'], { animate: true })
|
||||||
} else {
|
} else {
|
||||||
@ -1161,6 +1204,7 @@ export class CustomZoom extends Zoom {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
if (this.controlOption.showZoom) {
|
if (this.controlOption.showZoom) {
|
||||||
this['zoomNumDiv'] = this['createButton'](
|
this['zoomNumDiv'] = this['createButton'](
|
||||||
@ -1208,7 +1252,11 @@ export class CustomZoom extends Zoom {
|
|||||||
} as IZoomControlOption
|
} as IZoomControlOption
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function configL7Zoom(chart: Chart, scene: Scene) {
|
export function configL7Zoom(
|
||||||
|
chart: Chart,
|
||||||
|
scene: Scene,
|
||||||
|
mapKey?: { key: string; securityCode: string; mapType: string }
|
||||||
|
) {
|
||||||
const { basicStyle } = parseJson(chart.customAttr)
|
const { basicStyle } = parseJson(chart.customAttr)
|
||||||
const zoomOption = scene?.getControlByName('zoom')
|
const zoomOption = scene?.getControlByName('zoom')
|
||||||
if (zoomOption) {
|
if (zoomOption) {
|
||||||
@ -1220,6 +1268,41 @@ export function configL7Zoom(chart: Chart, scene: Scene) {
|
|||||||
if (!scene?.getControlByName('zoom')) {
|
if (!scene?.getControlByName('zoom')) {
|
||||||
if (!scene.map) {
|
if (!scene.map) {
|
||||||
scene.once('loaded', () => {
|
scene.once('loaded', () => {
|
||||||
|
switch (mapKey?.mapType) {
|
||||||
|
case 'tianditu':
|
||||||
|
//天地图
|
||||||
|
{
|
||||||
|
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
|
||||||
|
const center =
|
||||||
|
basicStyle.autoFit === false
|
||||||
|
? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
|
||||||
|
: [scene.map.getCenter().getLng(), scene.map.getCenter().getLat()]
|
||||||
|
const newZoomOptions = {
|
||||||
|
initZoom: initZoom,
|
||||||
|
center: center,
|
||||||
|
buttonColor: basicStyle.zoomButtonColor,
|
||||||
|
buttonBackground: basicStyle.zoomBackground
|
||||||
|
} as any
|
||||||
|
scene.addControl(new CustomZoom(newZoomOptions))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'qq':
|
||||||
|
{
|
||||||
|
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
|
||||||
|
const center =
|
||||||
|
basicStyle.autoFit === false
|
||||||
|
? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]
|
||||||
|
: [scene.map.getCenter().lng, scene.map.getCenter().lat]
|
||||||
|
const newZoomOptions = {
|
||||||
|
initZoom: initZoom,
|
||||||
|
center: center,
|
||||||
|
buttonColor: basicStyle.zoomButtonColor,
|
||||||
|
buttonBackground: basicStyle.zoomBackground
|
||||||
|
} as any
|
||||||
|
scene.addControl(new CustomZoom(newZoomOptions))
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
scene.map.on('complete', () => {
|
scene.map.on('complete', () => {
|
||||||
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
|
const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom()
|
||||||
const center =
|
const center =
|
||||||
@ -1234,6 +1317,7 @@ export function configL7Zoom(chart: Chart, scene: Scene) {
|
|||||||
} as any
|
} as any
|
||||||
scene.addControl(new CustomZoom(newZoomOptions))
|
scene.addControl(new CustomZoom(newZoomOptions))
|
||||||
})
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
const newZoomOptions = {
|
const newZoomOptions = {
|
||||||
@ -1335,6 +1419,18 @@ export function mapRendering(dom: HTMLElement | string) {
|
|||||||
dom.classList.add('de-map-rendering')
|
dom.classList.add('de-map-rendering')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function qqMapRendered(scene?: Scene) {
|
||||||
|
if (scene?.map && scene.map.deMapProvider === 'qq') {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (scene.map) {
|
||||||
|
scene.map.deMapAutoZoom = scene.map.getZoom()
|
||||||
|
scene.map.deMapAutoLng = scene.map.getCenter().getLng()
|
||||||
|
scene.map.deMapAutoLat = scene.map.getCenter().getLat()
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function mapRendered(dom: HTMLElement | string) {
|
export function mapRendered(dom: HTMLElement | string) {
|
||||||
if (typeof dom === 'string') {
|
if (typeof dom === 'string') {
|
||||||
dom = document.getElementById(dom)
|
dom = document.getElementById(dom)
|
||||||
@ -1342,6 +1438,213 @@ export function mapRendered(dom: HTMLElement | string) {
|
|||||||
dom.classList.add('de-map-rendered')
|
dom.classList.add('de-map-rendered')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMapCenter(basicStyle: ChartBasicStyle) {
|
||||||
|
let center: [number, number]
|
||||||
|
if (basicStyle.autoFit === false) {
|
||||||
|
const longitude = basicStyle?.mapCenter?.longitude ?? DEFAULT_BASIC_STYLE.mapCenter.longitude
|
||||||
|
const latitude = basicStyle?.mapCenter?.latitude ?? DEFAULT_BASIC_STYLE.mapCenter.latitude
|
||||||
|
center = [longitude, latitude]
|
||||||
|
} else {
|
||||||
|
center = undefined
|
||||||
|
}
|
||||||
|
return center
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMapStyle(
|
||||||
|
mapKey: { key: string; securityCode: string; mapType: string },
|
||||||
|
basicStyle: ChartBasicStyle
|
||||||
|
) {
|
||||||
|
let mapStyle: string
|
||||||
|
switch (mapKey.mapType) {
|
||||||
|
case 'tianditu':
|
||||||
|
if (!find(tdtMapStyleOptions, s => s.value === basicStyle.mapStyle)) {
|
||||||
|
mapStyle = 'normal'
|
||||||
|
} else {
|
||||||
|
mapStyle = basicStyle.mapStyle
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'qq':
|
||||||
|
if (
|
||||||
|
!find(qqMapStyleOptions, s => s.value === basicStyle.mapStyle) ||
|
||||||
|
basicStyle.mapStyle === 'normal'
|
||||||
|
) {
|
||||||
|
mapStyle = 'normal'
|
||||||
|
} else {
|
||||||
|
mapStyle = basicStyle.mapStyleUrl
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (!find(gaodeMapStyleOptions, s => s.value === basicStyle.mapStyle)) {
|
||||||
|
basicStyle.mapStyle = 'normal'
|
||||||
|
}
|
||||||
|
mapStyle = basicStyle.mapStyleUrl
|
||||||
|
if (basicStyle.mapStyle !== 'custom') {
|
||||||
|
mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return mapStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMapScene(
|
||||||
|
chart: Chart,
|
||||||
|
scene: Scene,
|
||||||
|
container: string,
|
||||||
|
mapKey: { key: string; securityCode: string; mapType: string },
|
||||||
|
basicStyle: ChartBasicStyle,
|
||||||
|
miscStyle: ChartMiscAttr,
|
||||||
|
mapStyle: string,
|
||||||
|
center?: [number, number]
|
||||||
|
) {
|
||||||
|
if (!scene) {
|
||||||
|
scene = new Scene({
|
||||||
|
id: container,
|
||||||
|
logoVisible: false,
|
||||||
|
map: getMapObject(mapKey, basicStyle, miscStyle, mapStyle, center)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
if (mapKey.mapType === 'tianditu') {
|
||||||
|
scene.map?.checkResize()
|
||||||
|
}
|
||||||
|
if (scene.getLayers()?.length) {
|
||||||
|
await scene.removeAllLayer()
|
||||||
|
try {
|
||||||
|
scene.setPitch(miscStyle.mapPitch)
|
||||||
|
} catch (e) {}
|
||||||
|
if (mapKey.mapType === 'tianditu') {
|
||||||
|
if (mapStyle === 'normal') {
|
||||||
|
scene.map?.removeStyle()
|
||||||
|
} else {
|
||||||
|
scene.setMapStyle(mapStyle)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
scene.setMapStyle(mapStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.map.showLabel = !(basicStyle.showLabel === false)
|
||||||
|
if (mapKey.mapType === 'qq') {
|
||||||
|
scene.map.setBaseMap({
|
||||||
|
//底图设置(参数为:VectorBaseMap对象)
|
||||||
|
type: 'vector', //类型:失量底图
|
||||||
|
features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined
|
||||||
|
//仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (basicStyle.autoFit === false) {
|
||||||
|
scene.setZoomAndCenter(basicStyle.zoomLevel, center)
|
||||||
|
if (mapKey.mapType === 'qq') {
|
||||||
|
scene.map.deMapAutoFit = false
|
||||||
|
scene.map.deMapZoom = basicStyle.zoomLevel
|
||||||
|
scene.map.deMapCenter = center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mapRendering(container)
|
||||||
|
scene.once('loaded', () => {
|
||||||
|
mapRendered(container)
|
||||||
|
if (mapKey.mapType === 'qq') {
|
||||||
|
scene.map.setBaseMap({
|
||||||
|
//底图设置(参数为:VectorBaseMap对象)
|
||||||
|
type: 'vector', //类型:失量底图
|
||||||
|
features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined
|
||||||
|
//仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果
|
||||||
|
})
|
||||||
|
scene.setMapStyle(mapStyle)
|
||||||
|
|
||||||
|
scene.map.deMapProvider = 'qq'
|
||||||
|
scene.map.deMapAutoFit = !!basicStyle.autoFit
|
||||||
|
// scene.map.deMapAutoZoom = scene.map.getZoom()
|
||||||
|
// scene.map.deMapAutoLng = scene.map.getCenter().getLng()
|
||||||
|
// scene.map.deMapAutoLat = scene.map.getCenter().getLat()
|
||||||
|
}
|
||||||
|
// 去除天地图自己的缩放按钮
|
||||||
|
if (mapKey.mapType === 'tianditu') {
|
||||||
|
if (mapStyle === 'normal') {
|
||||||
|
scene.map?.removeStyle()
|
||||||
|
} else {
|
||||||
|
scene.setMapStyle(mapStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
const tdtControl = document.querySelector(
|
||||||
|
`#component${chart.id} .tdt-control-zoom.tdt-bar.tdt-control`
|
||||||
|
)
|
||||||
|
if (tdtControl) {
|
||||||
|
tdtControl.style.display = 'none'
|
||||||
|
}
|
||||||
|
const tdtControlOuter = document.querySelectorAll(
|
||||||
|
`#wrapper-outer-id-${chart.id} .tdt-control-zoom.tdt-bar.tdt-control`
|
||||||
|
)
|
||||||
|
if (tdtControlOuter && tdtControlOuter.length > 0) {
|
||||||
|
for (let i = 0; i < tdtControlOuter.length; i++) {
|
||||||
|
tdtControlOuter[i].style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const tdtCopyrightControl = document.querySelector(
|
||||||
|
`#component${chart.id} .tdt-control-copyright.tdt-control`
|
||||||
|
)
|
||||||
|
if (tdtCopyrightControl) {
|
||||||
|
tdtCopyrightControl.style.display = 'none'
|
||||||
|
}
|
||||||
|
const tdtCopyrightControlOuter = document.querySelectorAll(
|
||||||
|
`#wrapper-outer-id-${chart.id} .tdt-control-copyright.tdt-control`
|
||||||
|
)
|
||||||
|
if (tdtCopyrightControlOuter && tdtCopyrightControlOuter.length > 0) {
|
||||||
|
for (let i = 0; i < tdtCopyrightControlOuter.length; i++) {
|
||||||
|
tdtCopyrightControlOuter[i].style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return scene
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMapObject(
|
||||||
|
mapKey: { key: string; securityCode: string; mapType: string },
|
||||||
|
basicStyle: ChartBasicStyle,
|
||||||
|
miscStyle: ChartMiscAttr,
|
||||||
|
mapStyle: string,
|
||||||
|
center?: [number, number]
|
||||||
|
) {
|
||||||
|
switch (mapKey.mapType) {
|
||||||
|
case 'tianditu':
|
||||||
|
return new TMap({
|
||||||
|
token: mapKey?.key ?? undefined,
|
||||||
|
style: mapStyle, //不生效
|
||||||
|
pitch: undefined, //不支持
|
||||||
|
center,
|
||||||
|
zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined,
|
||||||
|
showLabel: !(basicStyle.showLabel === false), //不支持
|
||||||
|
WebGLParams: {
|
||||||
|
preserveDrawingBuffer: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
case 'qq':
|
||||||
|
return new TencentMap({
|
||||||
|
token: mapKey?.key ?? undefined,
|
||||||
|
style: mapStyle,
|
||||||
|
pitch: miscStyle.mapPitch,
|
||||||
|
center,
|
||||||
|
zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : 12,
|
||||||
|
showLabel: !(basicStyle.showLabel === false),
|
||||||
|
WebGLParams: {
|
||||||
|
preserveDrawingBuffer: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return new GaodeMap({
|
||||||
|
token: mapKey?.key ?? undefined,
|
||||||
|
style: mapStyle,
|
||||||
|
pitch: miscStyle.mapPitch,
|
||||||
|
center,
|
||||||
|
zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined,
|
||||||
|
showLabel: !(basicStyle.showLabel === false),
|
||||||
|
WebGLParams: {
|
||||||
|
preserveDrawingBuffer: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 隐藏缩放控件
|
* 隐藏缩放控件
|
||||||
* @param basicStyle
|
* @param basicStyle
|
||||||
@ -1358,6 +1661,8 @@ export function getTooltipContainer(id) {
|
|||||||
let wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER)
|
let wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER)
|
||||||
if (!wrapperDom) {
|
if (!wrapperDom) {
|
||||||
wrapperDom = document.createElement('div')
|
wrapperDom = document.createElement('div')
|
||||||
|
wrapperDom.style.position = 'absolute'
|
||||||
|
wrapperDom.style.zIndex = '9999'
|
||||||
wrapperDom.id = G2_TOOLTIP_WRAPPER
|
wrapperDom.id = G2_TOOLTIP_WRAPPER
|
||||||
document.body.appendChild(wrapperDom)
|
document.body.appendChild(wrapperDom)
|
||||||
}
|
}
|
||||||
@ -1391,14 +1696,78 @@ export function getTooltipContainer(id) {
|
|||||||
}
|
}
|
||||||
return g2Tooltip
|
return g2Tooltip
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置提示轮播
|
||||||
|
* @param plot
|
||||||
|
* @param chart
|
||||||
|
*/
|
||||||
|
function configCarouselTooltip(plot, chart) {
|
||||||
|
const start = isSupport(chart.type) && !document.getElementById('multiplexingDrawer')
|
||||||
|
if (start) {
|
||||||
|
// 启用轮播
|
||||||
|
plot.once('afterrender', () => {
|
||||||
|
const carousel = chart.customAttr?.tooltip?.carousel
|
||||||
|
ChartCarouselTooltip.manage(plot, chart, {
|
||||||
|
xField: 'field',
|
||||||
|
duration: carousel.enable ? carousel?.stayTime * 1000 : 2000,
|
||||||
|
interval: carousel.enable ? carousel?.intervalTime * 1000 : 2000
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 计算 Tooltip 的位置
|
||||||
|
* @param {Chart} chart - 图表实例
|
||||||
|
* @param {boolean} isCarousel - 是否为轮播模式
|
||||||
|
* @param {object} tooltipCtl - Tooltip 控制器
|
||||||
|
* @param {HTMLElement} chartElement - 图表元素
|
||||||
|
* @param {Event} event - 事件对象
|
||||||
|
* @param {boolean} enlargeElement - 放大弹窗
|
||||||
|
* @returns {{x: number, y: number}} - 计算后的 x 和 y 坐标
|
||||||
|
*/
|
||||||
|
function calculateTooltipPosition(chart, isCarousel, tooltipCtl, chartElement, event) {
|
||||||
|
// 辅助函数: 根据不同图表类型计算 Tooltip 的y位置
|
||||||
|
const getTooltipY = () => {
|
||||||
|
const top = Number(chartElement.getBoundingClientRect().top)
|
||||||
|
if (isColumn(chart.type)) {
|
||||||
|
return top + chartElement.getBoundingClientRect().height / 2
|
||||||
|
}
|
||||||
|
if (isMix(chart.type) || isPie(chart.type)) {
|
||||||
|
return top + tooltipCtl.point.y
|
||||||
|
}
|
||||||
|
return top + tooltipCtl.point.y + 60
|
||||||
|
}
|
||||||
|
if (isCarousel) {
|
||||||
|
return {
|
||||||
|
x: tooltipCtl.point.x + Number(chartElement.getBoundingClientRect().left),
|
||||||
|
y: getTooltipY()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return { x: event.clientX, y: event.clientY }
|
||||||
|
}
|
||||||
|
}
|
||||||
export function configPlotTooltipEvent<O extends PickOptions, P extends Plot<O>>(
|
export function configPlotTooltipEvent<O extends PickOptions, P extends Plot<O>>(
|
||||||
chart: Chart,
|
chart: Chart,
|
||||||
plot: P
|
plot: P
|
||||||
) {
|
) {
|
||||||
const { tooltip } = parseJson(chart.customAttr)
|
const { tooltip } = parseJson(chart.customAttr)
|
||||||
if (!tooltip.show) {
|
if (!tooltip.show) {
|
||||||
|
ChartCarouselTooltip.destroyByContainer(chart.container)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 图表容器,用于计算 tooltip 的位置
|
||||||
|
// 获取图表元素,优先顺序:放大 > 预览 > 公共连接页面 > 默认
|
||||||
|
const chartElement =
|
||||||
|
document.getElementById('container-viewDialog-' + chart.id + '-common') ||
|
||||||
|
document.getElementById('container-preview-' + chart.id + '-common') ||
|
||||||
|
document.getElementById('enlarge-inner-content-' + chart.id) ||
|
||||||
|
document.getElementById('shape-id-' + chart.id)
|
||||||
|
// 是否是放大弹窗
|
||||||
|
const enlargeElement = chartElement?.id.includes('viewDialog')
|
||||||
|
// 轮播时tooltip的zIndex
|
||||||
|
const carousel_zIndex = enlargeElement ? '9999' : '1002'
|
||||||
|
configCarouselTooltip(plot, chart)
|
||||||
// 鼠标可移入, 移入之后保持显示, 移出之后隐藏
|
// 鼠标可移入, 移入之后保持显示, 移出之后隐藏
|
||||||
plot.options.tooltip.container.addEventListener('mouseenter', e => {
|
plot.options.tooltip.container.addEventListener('mouseenter', e => {
|
||||||
e.target.style.visibility = 'visible'
|
e.target.style.visibility = 'visible'
|
||||||
@ -1415,10 +1784,25 @@ export function configPlotTooltipEvent<O extends PickOptions, P extends Plot<O>>
|
|||||||
if (!tooltipCtl) {
|
if (!tooltipCtl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// 处理 tooltip 与下拉菜单的显示冲突问题
|
||||||
|
const viewTrackBarElement = document.getElementById('view-track-bar-' + chart.id)
|
||||||
const event = plot.chart.interactions.tooltip?.context?.event
|
const event = plot.chart.interactions.tooltip?.context?.event
|
||||||
|
// 是否时轮播模式
|
||||||
|
const isCarousel =
|
||||||
|
chart.customAttr?.tooltip?.carousel &&
|
||||||
|
(!event || // 事件触发时,使用event的client坐标
|
||||||
|
['plot:leave', 'plot:mouseleave'].includes(event?.type) || //鼠标离开时,使用tooltipCtl.point
|
||||||
|
['pie', 'pie-rose', 'pie-donut'].includes(chart.type)) // 饼图时,使用tooltipCtl.point
|
||||||
|
plot.options.tooltip.showMarkers = isCarousel ? true : false
|
||||||
|
const wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER)
|
||||||
|
wrapperDom.style.zIndex = isCarousel && wrapperDom ? carousel_zIndex : '9999'
|
||||||
if (tooltipCtl.tooltip) {
|
if (tooltipCtl.tooltip) {
|
||||||
// 处理视图放大后再关闭 tooltip 的 dom 被清除
|
// 处理视图放大后再关闭 tooltip 的 dom 被清除
|
||||||
const container = tooltipCtl.tooltip.cfg.container
|
const container = tooltipCtl.tooltip.cfg.container
|
||||||
|
// 当下拉菜单不显示时,移除tooltip的hidden-tooltip样式
|
||||||
|
if (viewTrackBarElement?.getAttribute('aria-expanded') === 'false') {
|
||||||
|
container.classList.toggle('hidden-tooltip', false)
|
||||||
|
}
|
||||||
container.style.display = 'block'
|
container.style.display = 'block'
|
||||||
const dom = document.getElementById(container.id)
|
const dom = document.getElementById(container.id)
|
||||||
if (!dom) {
|
if (!dom) {
|
||||||
@ -1433,8 +1817,17 @@ export function configPlotTooltipEvent<O extends PickOptions, P extends Plot<O>>
|
|||||||
}
|
}
|
||||||
plot.chart.getOptions().tooltip.follow = false
|
plot.chart.getOptions().tooltip.follow = false
|
||||||
tooltipCtl.title = Math.random().toString()
|
tooltipCtl.title = Math.random().toString()
|
||||||
plot.chart.getTheme().components.tooltip.x = event.clientX
|
// 当显示提示为事件触发时,使用event的client坐标,否则使用tooltipCtl.point 数据点的位置,在图表中,需要加上图表在绘制区的位置
|
||||||
plot.chart.getTheme().components.tooltip.y = event.clientY
|
const { x, y } = calculateTooltipPosition(
|
||||||
|
chart,
|
||||||
|
isCarousel,
|
||||||
|
tooltipCtl,
|
||||||
|
chartElement,
|
||||||
|
event,
|
||||||
|
enlargeElement
|
||||||
|
)
|
||||||
|
plot.chart.getTheme().components.tooltip.x = x
|
||||||
|
plot.chart.getTheme().components.tooltip.y = y
|
||||||
})
|
})
|
||||||
// https://github.com/antvis/G2/blob/master/src/chart/controller/tooltip.ts#hideTooltip
|
// https://github.com/antvis/G2/blob/master/src/chart/controller/tooltip.ts#hideTooltip
|
||||||
plot.on('plot:leave', () => {
|
plot.on('plot:leave', () => {
|
||||||
@ -1457,14 +1850,22 @@ export function configPlotTooltipEvent<O extends PickOptions, P extends Plot<O>>
|
|||||||
if (!tooltipCtl) {
|
if (!tooltipCtl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const container = tooltipCtl.tooltip.cfg.container
|
const container = tooltipCtl.tooltip?.cfg.container
|
||||||
for (const ele of wrapperDom.children) {
|
for (const ele of wrapperDom.children) {
|
||||||
if (container.id !== ele.id) {
|
if (!container || container.id !== ele.id) {
|
||||||
ele.style.display = 'none'
|
ele.style.display = 'none'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
plot.on('tooltip:hidden', () => {
|
||||||
|
const tooltipCtl = plot.chart.getController('tooltip')
|
||||||
|
if (!tooltipCtl) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const container = tooltipCtl.tooltip?.cfg.container
|
||||||
|
container && (container.style.display = 'none')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TOOLTIP_TPL =
|
export const TOOLTIP_TPL =
|
||||||
@ -1699,10 +2100,12 @@ export function configYaxisTitleLengthLimit(chart, plot) {
|
|||||||
? wrappedTitle.slice(0, wrappedTitle.length - 2) + '...'
|
? wrappedTitle.slice(0, wrappedTitle.length - 2) + '...'
|
||||||
: wrappedTitle + '...'
|
: wrappedTitle + '...'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新Y轴标题的原始文本和截断后的文本
|
// 更新Y轴标题的原始文本和截断后的文本
|
||||||
ev.view.options.axes.yAxisExt.title.originalText = yAxis.name
|
const { title } = ev.view.options.axes.yAxisExt
|
||||||
ev.view.options.axes.yAxisExt.title.text = wrappedTitle
|
if (title) {
|
||||||
|
title.originalText = yAxis.name
|
||||||
|
title.text = wrappedTitle
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1731,7 +2134,7 @@ export const addConditionsStyleColorToData = (chart: Chart, options) => {
|
|||||||
})
|
})
|
||||||
} else if (item.quotaList?.length) {
|
} else if (item.quotaList?.length) {
|
||||||
const quotaList = item.quotaList.map(q => q.id) ?? []
|
const quotaList = item.quotaList.map(q => q.id) ?? []
|
||||||
quotaList.forEach((q, index) => {
|
quotaList.forEach(q => {
|
||||||
// 定义后,在 handleConditionsStyle 函数中使用
|
// 定义后,在 handleConditionsStyle 函数中使用
|
||||||
let currentValue = item[valueField]
|
let currentValue = item[valueField]
|
||||||
if (chart.type === 'progress-bar') {
|
if (chart.type === 'progress-bar') {
|
||||||
@ -1798,7 +2201,7 @@ const getColorByConditions = (quotaList: [], values: number | number[], chart) =
|
|||||||
* @param chart
|
* @param chart
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
export function handleConditionsStyle(chart: Chart, options: O) {
|
export function handleConditionsStyle(chart: Chart, options) {
|
||||||
const { threshold } = parseJson(chart.senior)
|
const { threshold } = parseJson(chart.senior)
|
||||||
if (!threshold.enable) return options
|
if (!threshold.enable) return options
|
||||||
const { basicStyle } = parseJson(chart.customAttr)
|
const { basicStyle } = parseJson(chart.customAttr)
|
||||||
@ -1810,8 +2213,6 @@ export function handleConditionsStyle(chart: Chart, options: O) {
|
|||||||
// 辅助函数:配置柱条样式颜色,条形图为barStyle,柱形图为columnStyle
|
// 辅助函数:配置柱条样式颜色,条形图为barStyle,柱形图为columnStyle
|
||||||
const columnStyle = data => {
|
const columnStyle = data => {
|
||||||
return {
|
return {
|
||||||
...options.columnStyle,
|
|
||||||
...options.barStyle,
|
|
||||||
...(data[colorField]?.[0] ? { fill: data[colorField][0] } : {})
|
...(data[colorField]?.[0] ? { fill: data[colorField][0] } : {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1825,8 +2226,8 @@ export function handleConditionsStyle(chart: Chart, options: O) {
|
|||||||
const tmpOption = {
|
const tmpOption = {
|
||||||
...options,
|
...options,
|
||||||
rawFields,
|
rawFields,
|
||||||
columnStyle: columnStyle,
|
...configRoundAngle(chart, 'columnStyle', columnStyle),
|
||||||
barStyle: columnStyle,
|
...configRoundAngle(chart, 'barStyle', columnStyle),
|
||||||
tooltip: {
|
tooltip: {
|
||||||
...options.tooltip,
|
...options.tooltip,
|
||||||
...(options.tooltip['customItems']
|
...(options.tooltip['customItems']
|
||||||
@ -1934,7 +2335,7 @@ export const getTooltipItemConditionColor = item => {
|
|||||||
* @param newData
|
* @param newData
|
||||||
* @param container
|
* @param container
|
||||||
*/
|
*/
|
||||||
export const configEmptyDataStyle = (newChart, newData, container) => {
|
export const configEmptyDataStyle = (newData, container, newChart?, content?) => {
|
||||||
/**
|
/**
|
||||||
* 辅助函数:移除空数据dom
|
* 辅助函数:移除空数据dom
|
||||||
*/
|
*/
|
||||||
@ -1949,15 +2350,121 @@ export const configEmptyDataStyle = (newChart, newData, container) => {
|
|||||||
if (!newData.length) {
|
if (!newData.length) {
|
||||||
const emptyDom = document.createElement('div')
|
const emptyDom = document.createElement('div')
|
||||||
emptyDom.id = container + '_empty'
|
emptyDom.id = container + '_empty'
|
||||||
emptyDom.textContent = tI18n('data_set.no_data')
|
emptyDom.textContent = content || tI18n('data_set.no_data')
|
||||||
emptyDom.setAttribute(
|
emptyDom.setAttribute(
|
||||||
'style',
|
'style',
|
||||||
`position: absolute;
|
`position: absolute;
|
||||||
left: 45%;
|
left: 50%;
|
||||||
top: 50%;`
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: darkgray;
|
||||||
|
textAlign: center;`
|
||||||
)
|
)
|
||||||
const parent = document.getElementById(container)
|
const parent = document.getElementById(container)
|
||||||
parent.insertBefore(emptyDom, parent.firstChild)
|
parent.insertBefore(emptyDom, parent.firstChild)
|
||||||
newChart.destroy()
|
newChart?.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const numberToChineseUnderHundred = (num: number): string => {
|
||||||
|
// 合法性检查
|
||||||
|
if (num <= 0 || num > 99 || !Number.isInteger(num)) {
|
||||||
|
throw new Error('请输入1-99之间的整数')
|
||||||
|
}
|
||||||
|
|
||||||
|
const digits = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九']
|
||||||
|
|
||||||
|
// 处理个位数
|
||||||
|
if (num < 10) return digits[num]
|
||||||
|
|
||||||
|
const tens = Math.floor(num / 10)
|
||||||
|
const ones = num % 10
|
||||||
|
|
||||||
|
// 处理整十
|
||||||
|
if (ones === 0) {
|
||||||
|
return tens === 1 ? '十' : digits[tens] + '十'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理其他两位数
|
||||||
|
return tens === 1 ? '十' + digits[ones] : digits[tens] + '十' + digits[ones]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置柱条图的圆角
|
||||||
|
* @param styleName
|
||||||
|
* @param callBack 自定义其他属性函数
|
||||||
|
*/
|
||||||
|
export const configRoundAngle = (chart: Chart, styleName: string, callBack?: (datum) => {}) => {
|
||||||
|
const { basicStyle } = parseJson(chart.customAttr)
|
||||||
|
if (['roundAngle', 'topRoundAngle'].includes(basicStyle.radiusColumnBar)) {
|
||||||
|
const radius = Array(2).fill(basicStyle.columnBarRightAngleRadius)
|
||||||
|
const topRadius = [0, 0, ...radius]
|
||||||
|
const bottomRadius = [...radius, 0, 0]
|
||||||
|
const finalRadius = [...radius, ...radius]
|
||||||
|
if (chart.type.includes('-stack')) {
|
||||||
|
return {
|
||||||
|
[styleName]: datum => {
|
||||||
|
if (!datum.value) return { radius: [], ...(callBack ? callBack(datum) : {}) }
|
||||||
|
return { radius: finalRadius, ...(callBack ? callBack(datum) : {}) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const isTopRound = basicStyle.radiusColumnBar === 'topRoundAngle'
|
||||||
|
// 对称条形图
|
||||||
|
if (chart.type === 'bidirectional-bar') {
|
||||||
|
const valueField = basicStyle.layout === 'vertical' ? 'valueExt' : 'value'
|
||||||
|
return {
|
||||||
|
[styleName]: datum => ({
|
||||||
|
radius: datum[valueField] && isTopRound ? topRadius : isTopRound ? radius : finalRadius,
|
||||||
|
...(callBack ? callBack(datum) : {})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 进度条
|
||||||
|
if (chart.type === 'progress-bar') {
|
||||||
|
return {
|
||||||
|
[styleName]: datum => {
|
||||||
|
return {
|
||||||
|
radius: isTopRound ? bottomRadius : finalRadius,
|
||||||
|
...(callBack ? callBack(datum) : {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 区间条形图
|
||||||
|
if (chart.type === 'bar-range') {
|
||||||
|
return {
|
||||||
|
[styleName]: datum => {
|
||||||
|
return {
|
||||||
|
radius:
|
||||||
|
datum?.values[0] < datum?.values[1]
|
||||||
|
? isTopRound
|
||||||
|
? bottomRadius
|
||||||
|
: finalRadius
|
||||||
|
: isTopRound
|
||||||
|
? topRadius
|
||||||
|
: finalRadius,
|
||||||
|
...(callBack ? callBack(datum) : {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 配置柱条样式
|
||||||
|
const style = datum => {
|
||||||
|
if (isTopRound) {
|
||||||
|
return { radius, ...(callBack ? callBack(datum) : {}) }
|
||||||
|
}
|
||||||
|
if (!isTopRound) {
|
||||||
|
return { radius: finalRadius, ...(callBack ? callBack(datum) : {}) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
[styleName]: style
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
[styleName]: datum => {
|
||||||
|
return { ...(callBack ? callBack(datum) : {}) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,9 @@ import {
|
|||||||
isAlphaColor,
|
isAlphaColor,
|
||||||
isTransparent,
|
isTransparent,
|
||||||
parseJson,
|
parseJson,
|
||||||
resetRgbOpacity
|
resetRgbOpacity,
|
||||||
|
safeDecimalSum,
|
||||||
|
safeDecimalMean
|
||||||
} from '../..//util'
|
} from '../..//util'
|
||||||
import {
|
import {
|
||||||
DEFAULT_BASIC_STYLE,
|
DEFAULT_BASIC_STYLE,
|
||||||
@ -43,13 +45,31 @@ import {
|
|||||||
updateShapeAttr,
|
updateShapeAttr,
|
||||||
ViewMeta
|
ViewMeta
|
||||||
} from '@antv/s2'
|
} from '@antv/s2'
|
||||||
import { cloneDeep, filter, find, intersection, keys, merge, repeat } from 'lodash-es'
|
import {
|
||||||
|
cloneDeep,
|
||||||
|
filter,
|
||||||
|
find,
|
||||||
|
intersection,
|
||||||
|
keys,
|
||||||
|
map,
|
||||||
|
maxBy,
|
||||||
|
meanBy,
|
||||||
|
merge,
|
||||||
|
minBy,
|
||||||
|
repeat,
|
||||||
|
sumBy,
|
||||||
|
size,
|
||||||
|
sum
|
||||||
|
} from 'lodash-es'
|
||||||
import { createVNode, render } from 'vue'
|
import { createVNode, render } from 'vue'
|
||||||
import TableTooltip from '@/views/chart/components/editor/common/TableTooltip.vue'
|
import TableTooltip from '@/views/chart/components/editor/common/TableTooltip.vue'
|
||||||
import Exceljs from 'exceljs'
|
import Exceljs from 'exceljs'
|
||||||
import { saveAs } from 'file-saver'
|
import { saveAs } from 'file-saver'
|
||||||
import { ElMessage } from 'element-plus-secondary'
|
import { ElMessage } from 'element-plus-secondary'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
|
||||||
const { t: i18nt } = useI18n()
|
const { t: i18nt } = useI18n()
|
||||||
|
|
||||||
export function getCustomTheme(chart: Chart): S2Theme {
|
export function getCustomTheme(chart: Chart): S2Theme {
|
||||||
@ -401,8 +421,7 @@ export function getCustomTheme(chart: Chart): S2Theme {
|
|||||||
},
|
},
|
||||||
dataCell: {
|
dataCell: {
|
||||||
cell: {
|
cell: {
|
||||||
crossBackgroundColor:
|
crossBackgroundColor: enableTableCrossBG ? tableItemSubBgColor : tableItemBgColor,
|
||||||
enableTableCrossBG && !tableCell.mergeCells ? tableItemSubBgColor : tableItemBgColor,
|
|
||||||
backgroundColor: tableItemBgColor
|
backgroundColor: tableItemBgColor
|
||||||
},
|
},
|
||||||
bolderText: {
|
bolderText: {
|
||||||
@ -603,7 +622,7 @@ export function getConditions(chart: Chart) {
|
|||||||
const dimFields = [...chart.xAxis, ...chart.xAxisExt].map(i => i.dataeaseName)
|
const dimFields = [...chart.xAxis, ...chart.xAxisExt].map(i => i.dataeaseName)
|
||||||
if (conditions?.length > 0) {
|
if (conditions?.length > 0) {
|
||||||
const { tableCell, basicStyle, tableHeader } = parseJson(chart.customAttr)
|
const { tableCell, basicStyle, tableHeader } = parseJson(chart.customAttr)
|
||||||
// 合并单元格时,班马纹失效
|
// 合并单元格时斑马纹失效
|
||||||
const enableTableCrossBG =
|
const enableTableCrossBG =
|
||||||
chart.type === 'table-info'
|
chart.type === 'table-info'
|
||||||
? tableCell.enableTableCrossBG && !tableCell.mergeCells
|
? tableCell.enableTableCrossBG && !tableCell.mergeCells
|
||||||
@ -783,6 +802,9 @@ export function mappingColor(value, defaultColor, field, type, filedValueMap?, r
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// time
|
// time
|
||||||
|
if (!tv || !value) {
|
||||||
|
break
|
||||||
|
}
|
||||||
const fc = field.conditions[i]
|
const fc = field.conditions[i]
|
||||||
tv = new Date(tv.replace(/-/g, '/') + ' GMT+8').getTime()
|
tv = new Date(tv.replace(/-/g, '/') + ' GMT+8').getTime()
|
||||||
const v = new Date(value.replace(/-/g, '/') + ' GMT+8').getTime()
|
const v = new Date(value.replace(/-/g, '/') + ' GMT+8').getTime()
|
||||||
@ -880,6 +902,7 @@ export function handleTableEmptyStrategy(chart: Chart) {
|
|||||||
}
|
}
|
||||||
return newData
|
return newData
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SortTooltip extends BaseTooltip {
|
export class SortTooltip extends BaseTooltip {
|
||||||
show(showOptions) {
|
show(showOptions) {
|
||||||
const { iconName } = showOptions
|
const { iconName } = showOptions
|
||||||
@ -934,6 +957,7 @@ export class SortTooltip extends BaseTooltip {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SORT_DEFAULT =
|
const SORT_DEFAULT =
|
||||||
'<svg t="1711681787276" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4355" width="200" height="200"><path d="M922.345786 372.183628l-39.393195 38.687114L676.138314 211.079416l0 683.909301-54.713113 0L621.425202 129.010259l53.320393 0L922.345786 372.183628zM349.254406 894.989741 101.654214 651.815349l39.393195-38.687114 206.814276 199.792349L347.861686 129.010259l54.713113 0 0 765.978459L349.254406 894.988718z" fill="{fill}" p-id="4356"></path></svg>'
|
'<svg t="1711681787276" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4355" width="200" height="200"><path d="M922.345786 372.183628l-39.393195 38.687114L676.138314 211.079416l0 683.909301-54.713113 0L621.425202 129.010259l53.320393 0L922.345786 372.183628zM349.254406 894.989741 101.654214 651.815349l39.393195-38.687114 206.814276 199.792349L347.861686 129.010259l54.713113 0 0 765.978459L349.254406 894.988718z" fill="{fill}" p-id="4356"></path></svg>'
|
||||||
const SORT_UP =
|
const SORT_UP =
|
||||||
@ -1063,7 +1087,14 @@ export function copyContent(s2Instance: SpreadSheet, event, fieldMeta) {
|
|||||||
if (cells.length === 1) {
|
if (cells.length === 1) {
|
||||||
const curCell = cells[0]
|
const curCell = cells[0]
|
||||||
if (cell.getMeta().id === curCell.id) {
|
if (cell.getMeta().id === curCell.id) {
|
||||||
copyString(cellMeta.value + '', true)
|
const cellMeta = cell.getMeta()
|
||||||
|
const value = cellMeta.data?.[cellMeta.valueField]
|
||||||
|
const metaObj = find(fieldMeta, m => m.field === cellMeta.valueField)
|
||||||
|
let fieldVal = value?.toString()
|
||||||
|
if (metaObj) {
|
||||||
|
fieldVal = metaObj.formatter(value)
|
||||||
|
}
|
||||||
|
copyString(fieldVal, true)
|
||||||
}
|
}
|
||||||
s2Instance.interaction.clearState()
|
s2Instance.interaction.clearState()
|
||||||
return
|
return
|
||||||
@ -1189,7 +1220,7 @@ export async function exportGridPivot(instance: PivotSheet, chart: ChartObj) {
|
|||||||
const { meta, fields } = instance.dataCfg
|
const { meta, fields } = instance.dataCfg
|
||||||
const rowLength = fields?.rows?.length || 0
|
const rowLength = fields?.rows?.length || 0
|
||||||
const colLength = fields?.columns?.length || 0
|
const colLength = fields?.columns?.length || 0
|
||||||
const colNums = layoutResult.colLeafNodes.length + rowLength + 1
|
const colNums = layoutResult.colLeafNodes.length + rowLength
|
||||||
if (colNums > 16384) {
|
if (colNums > 16384) {
|
||||||
ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed'))
|
ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed'))
|
||||||
return
|
return
|
||||||
@ -1346,9 +1377,180 @@ export async function exportGridPivot(instance: PivotSheet, chart: ChartObj) {
|
|||||||
if (fieldValue === 0 || fieldValue) {
|
if (fieldValue === 0 || fieldValue) {
|
||||||
const meta = metaMap[dataCellMeta.valueField]
|
const meta = metaMap[dataCellMeta.valueField]
|
||||||
const cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 1)
|
const cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 1)
|
||||||
const value = meta?.formatter?.(fieldValue) || fieldValue.toString()
|
const value = meta?.formatter?.(fieldValue) || fieldValue
|
||||||
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.value = isNumeric(value) ? parseFloat(value) : value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const buffer = await workbook.xlsx.writeBuffer()
|
||||||
|
const dataBlob = new Blob([buffer], {
|
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'
|
||||||
|
})
|
||||||
|
saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function exportRowQuotaGridPivot(instance: PivotSheet, chart: ChartObj) {
|
||||||
|
const { layoutResult } = instance.facet
|
||||||
|
const { meta, fields } = instance.dataCfg
|
||||||
|
const rowLength = fields?.rows?.length || 0
|
||||||
|
const colLength = fields?.columns?.length || 0
|
||||||
|
const colNums = layoutResult.colLeafNodes.length + rowLength
|
||||||
|
if (colNums > 16384) {
|
||||||
|
ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const workbook = new Exceljs.Workbook()
|
||||||
|
const worksheet = workbook.addWorksheet(i18nt('chart.chart_data'))
|
||||||
|
const metaMap: Record<string, Meta> = meta?.reduce((p, n) => {
|
||||||
|
if (n.field) {
|
||||||
|
p[n.field] = n
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}, {})
|
||||||
|
// 角头
|
||||||
|
if (colLength > 1) {
|
||||||
|
fields.columns.forEach((column: string, index) => {
|
||||||
|
if (index >= colLength - 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cell = worksheet.getCell(index + 1, 1)
|
||||||
|
cell.value = metaMap[column]?.name ?? column
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.border = {
|
||||||
|
right: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
worksheet.mergeCells(index + 1, 1, index + 1, rowLength + 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fields?.rows?.forEach((row, index) => {
|
||||||
|
const cell = worksheet.getCell(colLength === 0 ? 1 : colLength, index + 1)
|
||||||
|
cell.value = metaMap[row]?.name ?? row
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.border = { bottom: { style: 'thick', color: { argb: '00000000' } } }
|
||||||
|
})
|
||||||
|
const quotaColLabel = chart.customAttr.basicStyle.quotaColLabel ?? t('dataset.value')
|
||||||
|
const quotaColHeadCell = worksheet.getCell(colLength === 0 ? 1 : colLength, rowLength + 1)
|
||||||
|
quotaColHeadCell.value = quotaColLabel
|
||||||
|
quotaColHeadCell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
quotaColHeadCell.border = {
|
||||||
|
bottom: { style: 'thick', color: { argb: '00000000' } },
|
||||||
|
right: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
// 行头
|
||||||
|
const { rowLeafNodes, rowNodes } = layoutResult
|
||||||
|
const notLeafNodeHeightMap: Record<string, number> = {}
|
||||||
|
rowLeafNodes.forEach(node => {
|
||||||
|
// 行头的高度由子节点相加决定,也就是行头子节点中包含的叶子节点数量
|
||||||
|
let curNode = node.parent
|
||||||
|
while (curNode) {
|
||||||
|
const height = notLeafNodeHeightMap[curNode.id] ?? 0
|
||||||
|
notLeafNodeHeightMap[curNode.id] = height + 1
|
||||||
|
curNode = curNode.parent
|
||||||
|
}
|
||||||
|
const { rowIndex } = node
|
||||||
|
const writeRowIndex = rowIndex + 2 + (colLength === 0 ? 1 : colLength - 1)
|
||||||
|
const writeColIndex = node.level + 1
|
||||||
|
const cell = worksheet.getCell(writeRowIndex, writeColIndex)
|
||||||
|
let value = node.label
|
||||||
|
if (node.field === '$$extra$$' && metaMap[value]?.name) {
|
||||||
|
value = metaMap[value].name
|
||||||
|
}
|
||||||
cell.value = value
|
cell.value = value
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.border = {
|
||||||
|
right: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getNodeStartRowIndex = (node: Node) => {
|
||||||
|
if (!node.children?.length) {
|
||||||
|
return node.rowIndex + 1
|
||||||
|
} else {
|
||||||
|
return getNodeStartRowIndex(node.children[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rowNodes?.forEach(node => {
|
||||||
|
if (node.isLeaf) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const rowIndex = getNodeStartRowIndex(node)
|
||||||
|
const height = notLeafNodeHeightMap[node.id]
|
||||||
|
const writeRowIndex = rowIndex + 1 + (colLength === 0 ? 1 : colLength - 1)
|
||||||
|
const mergeColCount = node.children[0].level - node.level
|
||||||
|
const cell = worksheet.getCell(writeRowIndex, node.level + 1)
|
||||||
|
cell.value = node.label
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
if (mergeColCount > 1 || height > 1) {
|
||||||
|
worksheet.mergeCells(
|
||||||
|
writeRowIndex,
|
||||||
|
node.level + 1,
|
||||||
|
writeRowIndex + height - 1,
|
||||||
|
node.level + mergeColCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 列头
|
||||||
|
const { colLeafNodes, colNodes, colsHierarchy } = layoutResult
|
||||||
|
const maxColHeight = colsHierarchy.maxLevel + 1
|
||||||
|
const notLeafNodeWidthMap: Record<string, number> = {}
|
||||||
|
colLeafNodes.forEach(node => {
|
||||||
|
// 列头的宽度由子节点相加决定,也就是列头子节点中包含的叶子节点数量
|
||||||
|
let curNode = node.parent
|
||||||
|
while (curNode) {
|
||||||
|
const width = notLeafNodeWidthMap[curNode.id] ?? 0
|
||||||
|
notLeafNodeWidthMap[curNode.id] = width + 1
|
||||||
|
curNode = curNode.parent
|
||||||
|
}
|
||||||
|
const { colIndex } = node
|
||||||
|
const writeRowIndex = node.level + 1
|
||||||
|
const writeColIndex = colIndex + rowLength + 2
|
||||||
|
const cell = worksheet.getCell(writeRowIndex, writeColIndex)
|
||||||
|
const value = node.label
|
||||||
|
cell.value = value
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
if (writeRowIndex < maxColHeight) {
|
||||||
|
worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex)
|
||||||
|
}
|
||||||
|
cell.border = {
|
||||||
|
bottom: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const getNodeStartColIndex = (node: Node) => {
|
||||||
|
if (!node.children?.length) {
|
||||||
|
return node.colIndex + 1
|
||||||
|
} else {
|
||||||
|
return getNodeStartColIndex(node.children[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colNodes.forEach(node => {
|
||||||
|
if (node.isLeaf) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const colIndex = getNodeStartColIndex(node)
|
||||||
|
const width = notLeafNodeWidthMap[node.id]
|
||||||
|
const writeRowIndex = node.level + 1
|
||||||
|
const value = node.label
|
||||||
|
const writeColIndex = colIndex + rowLength + 1
|
||||||
|
const cell = worksheet.getCell(writeRowIndex, writeColIndex)
|
||||||
|
cell.value = value
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
if (width > 1) {
|
||||||
|
worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, writeColIndex + width - 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 单元格数据
|
||||||
|
for (let rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) {
|
||||||
|
for (let colIndex = 0; colIndex < colLeafNodes.length; colIndex++) {
|
||||||
|
const dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex)
|
||||||
|
const { fieldValue } = dataCellMeta
|
||||||
|
if (fieldValue === 0 || fieldValue) {
|
||||||
|
const meta = metaMap[dataCellMeta.valueField]
|
||||||
|
const cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 2)
|
||||||
|
const value = meta?.formatter?.(fieldValue) || fieldValue
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.value = isNumeric(value) ? parseFloat(value) : value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1361,7 +1563,7 @@ export async function exportGridPivot(instance: PivotSheet, chart: ChartObj) {
|
|||||||
|
|
||||||
export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) {
|
export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) {
|
||||||
const layoutResult = instance.facet.layoutResult
|
const layoutResult = instance.facet.layoutResult
|
||||||
if (layoutResult.colLeafNodes.length + 2 > 16384) {
|
if (layoutResult.colLeafNodes.length + 1 > 16384) {
|
||||||
ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed'))
|
ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1468,9 +1670,9 @@ export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) {
|
|||||||
if (fieldValue === 0 || fieldValue) {
|
if (fieldValue === 0 || fieldValue) {
|
||||||
const meta = metaMap[dataCellMeta.valueField]
|
const meta = metaMap[dataCellMeta.valueField]
|
||||||
const cell = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 1 + 1)
|
const cell = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 1 + 1)
|
||||||
const value = meta?.formatter?.(fieldValue) || fieldValue.toString()
|
const value = meta?.formatter?.(fieldValue) || fieldValue
|
||||||
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
cell.value = value
|
cell.value = isNumeric(value) ? parseFloat(value) : value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1480,6 +1682,135 @@ export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) {
|
|||||||
})
|
})
|
||||||
saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`)
|
saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function exportRowQuotaTreePivot(instance: PivotSheet, chart: ChartObj) {
|
||||||
|
const layoutResult = instance.facet.layoutResult
|
||||||
|
if (layoutResult.colLeafNodes.length + 1 > 16384) {
|
||||||
|
ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const { meta, fields } = instance.dataCfg
|
||||||
|
const colLength = fields?.columns?.length || 0
|
||||||
|
const workbook = new Exceljs.Workbook()
|
||||||
|
const worksheet = workbook.addWorksheet(i18nt('chart.chart_data'))
|
||||||
|
const metaMap: Record<string, Meta> = meta?.reduce((p, n) => {
|
||||||
|
if (n.field) {
|
||||||
|
p[n.field] = n
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
// 角头
|
||||||
|
fields.columns?.forEach((column, index) => {
|
||||||
|
if (index >= fields.columns.length - 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cell = worksheet.getCell(index + 1, 1)
|
||||||
|
cell.value = metaMap[column]?.name ?? column
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.border = {
|
||||||
|
right: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const quotaColLabel = chart.customAttr.basicStyle.quotaColLabel ?? t('dataset.value')
|
||||||
|
const maxColHeight = layoutResult.colsHierarchy.maxLevel + 1
|
||||||
|
const rowName = fields?.rows
|
||||||
|
?.map(row => metaMap[row]?.name ?? row)
|
||||||
|
.concat(quotaColLabel)
|
||||||
|
.join('/')
|
||||||
|
const cell = worksheet.getCell(colLength, 1)
|
||||||
|
cell.value = rowName
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.border = {
|
||||||
|
right: { style: 'thick', color: { argb: '00000000' } },
|
||||||
|
bottom: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
//行头
|
||||||
|
const { rowLeafNodes } = layoutResult
|
||||||
|
rowLeafNodes.forEach((node, index) => {
|
||||||
|
const cell = worksheet.getCell(maxColHeight + index + 1, 1)
|
||||||
|
let value = node.label
|
||||||
|
if (node.field === '$$extra$$' && metaMap[value]?.name) {
|
||||||
|
value = metaMap[value].name
|
||||||
|
}
|
||||||
|
cell.value = repeat(' ', node.level) + value
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'left' }
|
||||||
|
cell.border = {
|
||||||
|
right: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 列头
|
||||||
|
const notLeafNodeWidthMap: Record<string, number> = {}
|
||||||
|
const { colLeafNodes } = layoutResult
|
||||||
|
colLeafNodes.forEach(node => {
|
||||||
|
let curNode = node.parent
|
||||||
|
while (curNode) {
|
||||||
|
const width = notLeafNodeWidthMap[curNode.id] ?? 0
|
||||||
|
notLeafNodeWidthMap[curNode.id] = width + 1
|
||||||
|
curNode = curNode.parent
|
||||||
|
}
|
||||||
|
const { colIndex } = node
|
||||||
|
const writeRowIndex = node.level + 1
|
||||||
|
const writeColIndex = colIndex + 2
|
||||||
|
const cell = worksheet.getCell(writeRowIndex, writeColIndex)
|
||||||
|
cell.value = node.label
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
if (writeRowIndex < maxColHeight) {
|
||||||
|
worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex)
|
||||||
|
}
|
||||||
|
cell.border = {
|
||||||
|
bottom: { style: 'thick', color: { argb: '00000000' } }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const colNodes = layoutResult.colNodes
|
||||||
|
const getNodeStartIndex = (node: Node) => {
|
||||||
|
if (!node.children?.length) {
|
||||||
|
return node.colIndex + 1
|
||||||
|
} else {
|
||||||
|
return getNodeStartIndex(node.children[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colNodes.forEach(node => {
|
||||||
|
if (node.isLeaf) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const colIndex = getNodeStartIndex(node)
|
||||||
|
const width = notLeafNodeWidthMap[node.id]
|
||||||
|
const writeRowIndex = node.level + 1
|
||||||
|
const writeColIndex = colIndex + 1
|
||||||
|
const cell = worksheet.getCell(writeRowIndex, writeColIndex)
|
||||||
|
cell.value = node.label
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
if (width > 1) {
|
||||||
|
worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, writeColIndex + width - 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 单元格数据
|
||||||
|
for (let rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) {
|
||||||
|
for (let colIndex = 0; colIndex < colLeafNodes.length; colIndex++) {
|
||||||
|
const dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex)
|
||||||
|
const { fieldValue } = dataCellMeta
|
||||||
|
if (fieldValue === 0 || fieldValue) {
|
||||||
|
const meta = metaMap[dataCellMeta.valueField]
|
||||||
|
const cell = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 2)
|
||||||
|
const value = meta?.formatter?.(fieldValue) || fieldValue
|
||||||
|
cell.alignment = { vertical: 'middle', horizontal: 'center' }
|
||||||
|
cell.value = isNumeric(value) ? parseFloat(value) : value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const buffer = await workbook.xlsx.writeBuffer()
|
||||||
|
const dataBlob = new Blob([buffer], {
|
||||||
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'
|
||||||
|
})
|
||||||
|
saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function isNumeric(value: string): boolean {
|
||||||
|
return /^[+-]?\d+(\.\d+)?$/.test(value)
|
||||||
|
}
|
||||||
|
|
||||||
export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) {
|
export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) {
|
||||||
const { fields } = instance.dataCfg
|
const { fields } = instance.dataCfg
|
||||||
const rowLength = fields?.rows?.length || 0
|
const rowLength = fields?.rows?.length || 0
|
||||||
@ -1488,12 +1819,21 @@ export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) {
|
|||||||
ElMessage.warning(i18nt('chart.pivot_export_invalid_field'))
|
ElMessage.warning(i18nt('chart.pivot_export_invalid_field'))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const { quotaPosition } = chart.customAttr.basicStyle
|
||||||
if (chart.customAttr.basicStyle.tableLayoutMode !== 'tree') {
|
if (chart.customAttr.basicStyle.tableLayoutMode !== 'tree') {
|
||||||
|
if (quotaPosition === 'row') {
|
||||||
|
exportRowQuotaGridPivot(instance, chart)
|
||||||
|
} else {
|
||||||
exportGridPivot(instance, chart)
|
exportGridPivot(instance, chart)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (quotaPosition === 'row') {
|
||||||
|
exportRowQuotaTreePivot(instance, chart)
|
||||||
} else {
|
} else {
|
||||||
exportTreePivot(instance, chart)
|
exportTreePivot(instance, chart)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function configMergeCells(chart: Chart, options: S2Options, dataConfig: S2DataConfig) {
|
export function configMergeCells(chart: Chart, options: S2Options, dataConfig: S2DataConfig) {
|
||||||
const { mergeCells } = parseJson(chart.customAttr).tableCell
|
const { mergeCells } = parseJson(chart.customAttr).tableCell
|
||||||
@ -1571,6 +1911,7 @@ export function configMergeCells(chart: Chart, options: S2Options, dataConfig: S
|
|||||||
if (showIndex && meta.colIndex === 0) {
|
if (showIndex && meta.colIndex === 0) {
|
||||||
meta.fieldValue = getRowIndex(mergedCellsInfo, meta)
|
meta.fieldValue = getRowIndex(mergedCellsInfo, meta)
|
||||||
}
|
}
|
||||||
|
meta.deFieldType = fieldsMap[meta.valueField]?.deType
|
||||||
return new CustomMergedCell(sheet, cells, meta)
|
return new CustomMergedCell(sheet, cells, meta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1598,12 +1939,13 @@ export function getRowIndex(mergedCellsInfo: MergedCellInfo[][], meta: ViewMeta)
|
|||||||
}, 0)
|
}, 0)
|
||||||
return curRangeStartIndex - lostCells + 1
|
return curRangeStartIndex - lostCells + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
class CustomMergedCell extends MergedCell {
|
class CustomMergedCell extends MergedCell {
|
||||||
protected drawBackgroundShape() {
|
protected drawBackgroundShape() {
|
||||||
const allPoints = getPolygonPoints(this.cells)
|
const allPoints = getPolygonPoints(this.cells)
|
||||||
// 处理条件样式,这里没有用透明度
|
// 处理条件样式,这里没有用透明度
|
||||||
// 因为合并的单元格是单独的图层,透明度降低的话会显示底下未合并的单元格,需要单独处理被覆盖的单元格
|
// 因为合并的单元格是单独的图层,透明度降低的话会显示底下未合并的单元格,需要单独处理被覆盖的单元格
|
||||||
const { backgroundColor: fill, backgroundColorOpacity: fillOpacity } = this.getBackgroundColor()
|
const { backgroundColor: fill } = this.getBackgroundColor()
|
||||||
const cellTheme = this.theme.dataCell.cell
|
const cellTheme = this.theme.dataCell.cell
|
||||||
this.backgroundShape = renderPolygon(this, {
|
this.backgroundShape = renderPolygon(this, {
|
||||||
points: allPoints,
|
points: allPoints,
|
||||||
@ -1612,6 +1954,14 @@ class CustomMergedCell extends MergedCell {
|
|||||||
lineHeight: cellTheme.horizontalBorderWidth
|
lineHeight: cellTheme.horizontalBorderWidth
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawTextShape(): void {
|
||||||
|
if (this.meta.deFieldType === 7) {
|
||||||
|
drawImage.apply(this)
|
||||||
|
} else {
|
||||||
|
super.drawTextShape()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CustomDataCell extends TableDataCell {
|
export class CustomDataCell extends TableDataCell {
|
||||||
@ -1847,103 +2197,103 @@ const getWrapTextHeight = (wrapText, textStyle, spreadsheet, maxLines) => {
|
|||||||
return Math.min(lines, maxLines) * maxHeight
|
return Math.min(lines, maxLines) * maxHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 导出获取汇总行的函数
|
||||||
* 设置汇总行
|
export function getSummaryRow(data, axis, sumCon = []) {
|
||||||
* @param chart
|
const summaryObj = { SUMMARY: true }
|
||||||
* @param s2Options
|
for (let i = 0; i < axis.length; i++) {
|
||||||
* @param newData
|
const a = axis[i].dataeaseName
|
||||||
* @param tableHeader
|
let savedAxis = find(sumCon, s => s.field === a)
|
||||||
* @param basicStyle
|
if (savedAxis) {
|
||||||
* @param showSummary
|
if (savedAxis.summary == undefined) {
|
||||||
*/
|
savedAxis.summary = 'sum' // 默认汇总方式为求和
|
||||||
export const configSummaryRow = (
|
}
|
||||||
chart,
|
if (savedAxis.show == undefined) {
|
||||||
s2Options,
|
savedAxis.show = true // 默认显示汇总结果
|
||||||
newData,
|
}
|
||||||
tableHeader,
|
|
||||||
basicStyle,
|
|
||||||
showSummary
|
|
||||||
) => {
|
|
||||||
if (!showSummary || !newData.length) return
|
|
||||||
// 设置汇总行高度和表头一致
|
|
||||||
const heightByField = {}
|
|
||||||
heightByField[newData.length] = tableHeader.tableTitleHeight
|
|
||||||
s2Options.style.rowCfg = { heightByField }
|
|
||||||
// 计算汇总加入到数据里,冻结最后一行
|
|
||||||
s2Options.frozenTrailingRowCount = 1
|
|
||||||
const yAxis = chart.yAxis
|
|
||||||
const xAxis = chart.xAxis
|
|
||||||
const summaryObj = newData.reduce(
|
|
||||||
(p, n) => {
|
|
||||||
if (chart.type === 'table-info') {
|
|
||||||
xAxis
|
|
||||||
.filter(axis => [2, 3, 4].includes(axis.deType))
|
|
||||||
.forEach(axis => {
|
|
||||||
p[axis.dataeaseName] =
|
|
||||||
(parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
yAxis.forEach(axis => {
|
savedAxis = {
|
||||||
p[axis.dataeaseName] =
|
field: a,
|
||||||
(parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0)
|
summary: 'sum',
|
||||||
})
|
show: true
|
||||||
}
|
}
|
||||||
return p
|
|
||||||
},
|
|
||||||
{ SUMMARY: true }
|
|
||||||
)
|
|
||||||
newData.push(summaryObj)
|
|
||||||
s2Options.dataCell = viewMeta => {
|
|
||||||
// 配置文本自动换行参数
|
|
||||||
viewMeta.autoWrap = basicStyle.autoWrap
|
|
||||||
viewMeta.maxLines = basicStyle.maxLines
|
|
||||||
if (viewMeta.rowIndex !== newData.length - 1) {
|
|
||||||
return new CustomDataCell(viewMeta, viewMeta.spreadsheet)
|
|
||||||
}
|
}
|
||||||
if (viewMeta.colIndex === 0) {
|
// 如果配置为不显示,则跳过该字段
|
||||||
if (tableHeader.showIndex) {
|
if (!savedAxis.show) {
|
||||||
viewMeta.fieldValue = basicStyle.summaryLabel ?? i18nt('chart.total_show')
|
continue
|
||||||
|
}
|
||||||
|
// 根据汇总方式处理数据
|
||||||
|
switch (savedAxis.summary) {
|
||||||
|
case 'sum':
|
||||||
|
// 计算字段的总和
|
||||||
|
summaryObj[a] = safeDecimalSum(data, a)
|
||||||
|
break
|
||||||
|
case 'avg':
|
||||||
|
// 计算字段的平均值
|
||||||
|
summaryObj[a] = safeDecimalMean(data, a)
|
||||||
|
break
|
||||||
|
case 'max':
|
||||||
|
// 计算字段的最大值
|
||||||
|
summaryObj[a] = maxBy(
|
||||||
|
filter(data, d => parseFloat(d[a]) !== undefined),
|
||||||
|
d => parseFloat(d[a]) // 提取数值
|
||||||
|
)[a]
|
||||||
|
break
|
||||||
|
case 'min':
|
||||||
|
// 计算字段的最小值
|
||||||
|
summaryObj[a] = minBy(
|
||||||
|
filter(data, d => parseFloat(d[a]) !== undefined),
|
||||||
|
d => parseFloat(d[a]) // 提取数值
|
||||||
|
)[a]
|
||||||
|
break
|
||||||
|
case 'var_pop':
|
||||||
|
// 计算总体方差(需要至少2个数据点)
|
||||||
|
if (data.length < 2) {
|
||||||
|
continue
|
||||||
} else {
|
} else {
|
||||||
if (xAxis.length) {
|
const mean = safeDecimalMean(data, a) // 计算平均值
|
||||||
viewMeta.fieldValue = basicStyle.summaryLabel ?? i18nt('chart.total_show')
|
// 计算每个数据点与平均值的差的平方
|
||||||
|
const squaredDeviations = map(data, d => {
|
||||||
|
const value = new Decimal(d[a] ?? 0) // 获取字段值,如果不存在则使用0
|
||||||
|
const dev = value.minus(mean) // 计算差值
|
||||||
|
return dev.times(dev) // 计算平方
|
||||||
|
})
|
||||||
|
// 计算方差(平方差的平均值)
|
||||||
|
const variance = squaredDeviations.reduce((acc, val) => acc.plus(val), new Decimal(0))
|
||||||
|
summaryObj[a] = variance.dividedBy(data.length - 1).toNumber() // 计算总体方差
|
||||||
}
|
}
|
||||||
|
break
|
||||||
|
case 'stddev_pop':
|
||||||
|
// 计算总体标准差(需要至少2个数据点)
|
||||||
|
if (data.length < 2) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
const mean = safeDecimalMean(data, a) // 计算平均值
|
||||||
|
// 计算每个数据点与平均值的差的平方
|
||||||
|
const squaredDeviations = map(data, d => {
|
||||||
|
const value = new Decimal(d[a] ?? 0) // 获取字段值,如果不存在则使用0
|
||||||
|
const dev = value.minus(mean) // 计算差值
|
||||||
|
return dev.times(dev) // 计算平方
|
||||||
|
})
|
||||||
|
// 计算方差(平方差的平均值)
|
||||||
|
const variance = squaredDeviations.reduce((acc, val) => acc.plus(val), new Decimal(0))
|
||||||
|
summaryObj[a] = variance.dividedBy(data.length - 1).sqrt().toNumber() // 计算总体标准差
|
||||||
}
|
}
|
||||||
}
|
break
|
||||||
return new SummaryCell(viewMeta, viewMeta.spreadsheet)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// 返回汇总结果对象
|
||||||
* 汇总行样式,紧贴在单元格后面
|
return summaryObj
|
||||||
* @param newChart
|
|
||||||
* @param newData
|
|
||||||
* @param tableCell
|
|
||||||
* @param tableHeader
|
|
||||||
* @param showSummary
|
|
||||||
*/
|
|
||||||
export const summaryRowStyle = (newChart, newData, tableCell, tableHeader, showSummary) => {
|
|
||||||
if (!showSummary || !newData.length) return
|
|
||||||
newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => {
|
|
||||||
const showHeader = tableHeader.showTableHeader === true
|
|
||||||
// 不显示表头时,减少一个表头的高度
|
|
||||||
const headerAndSummaryHeight = showHeader ? 2 : 1
|
|
||||||
const totalHeight =
|
|
||||||
tableHeader.tableTitleHeight * headerAndSummaryHeight +
|
|
||||||
tableCell.tableItemHeight * (newData.length - 1)
|
|
||||||
if (totalHeight < newChart.options.height) {
|
|
||||||
// 6 是阴影高度
|
|
||||||
newChart.options.height =
|
|
||||||
totalHeight < newChart.options.height - 6 ? totalHeight + 6 : totalHeight
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class SummaryCell extends CustomDataCell {
|
export class SummaryCell extends CustomDataCell {
|
||||||
getTextStyle() {
|
getTextStyle() {
|
||||||
const textStyle = cloneDeep(this.theme.colCell.bolderText)
|
const textStyle = cloneDeep(this.theme.colCell.bolderText)
|
||||||
textStyle.textAlign = this.theme.dataCell.text.textAlign
|
textStyle.textAlign = this.theme.dataCell.text.textAlign
|
||||||
return textStyle
|
return textStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
getBackgroundColor() {
|
getBackgroundColor() {
|
||||||
const { backgroundColor, backgroundColorOpacity } = this.theme.colCell.cell
|
const { backgroundColor, backgroundColorOpacity } = this.theme.colCell.cell
|
||||||
return { backgroundColor, backgroundColorOpacity }
|
return { backgroundColor, backgroundColorOpacity }
|
||||||
@ -2019,3 +2369,27 @@ export const getColumns = (fields, cols: Array<ColumnNode>) => {
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function drawImage() {
|
||||||
|
const img = new Image()
|
||||||
|
const { x, y, width, height, fieldValue } = this.meta
|
||||||
|
img.src = fieldValue as string
|
||||||
|
img.setAttribute('crossOrigin', 'anonymous')
|
||||||
|
img.onload = () => {
|
||||||
|
!this.cfg.children && (this.cfg.children = [])
|
||||||
|
const { width: imgWidth, height: imgHeight } = img
|
||||||
|
const ratio = Math.max(imgWidth / width, imgHeight / height)
|
||||||
|
// 不铺满,部分留白
|
||||||
|
const imgShowWidth = (imgWidth / ratio) * 0.8
|
||||||
|
const imgShowHeight = (imgHeight / ratio) * 0.8
|
||||||
|
this.textShape = this.addShape('image', {
|
||||||
|
attrs: {
|
||||||
|
x: x + (imgShowWidth < width ? (width - imgShowWidth) / 2 : 0),
|
||||||
|
y: y + (imgShowHeight < height ? (height - imgShowHeight) / 2 : 0),
|
||||||
|
width: imgShowWidth,
|
||||||
|
height: imgShowHeight,
|
||||||
|
img
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -170,7 +170,7 @@ export abstract class G2PlotChartView<
|
|||||||
public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
||||||
return setupSeriesColor(chart, data)
|
return setupSeriesColor(chart, data)
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line
|
||||||
public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@ -191,8 +191,8 @@ export abstract class G2PlotChartView<
|
|||||||
return addConditionsStyleColorToData(chart, data)
|
return addConditionsStyleColorToData(chart, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected configEmptyDataStyle(newChart, newData: any[], container: string) {
|
protected configEmptyDataStyle(newData, container, newChart?, content?) {
|
||||||
configEmptyDataStyle(newChart, newData, container)
|
configEmptyDataStyle(newData, container, newChart, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,8 +107,8 @@ export abstract class L7ChartView<
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
protected configZoomButton(chart: Chart, plot: S) {
|
protected configZoomButton(chart: Chart, plot: S, mapKey?: any) {
|
||||||
configL7Zoom(chart, plot)
|
configL7Zoom(chart, plot, mapKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected configLabel(chart: Chart, options: O): O {
|
protected configLabel(chart: Chart, options: O): O {
|
||||||
|
@ -136,7 +136,6 @@ export abstract class S2ChartView<P extends SpreadSheet> extends AntVAbstractCha
|
|||||||
if (duration > 300) {
|
if (duration > 300) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const callback = () => {
|
|
||||||
const canvasPosition = canvas.getBoundingClientRect()
|
const canvasPosition = canvas.getBoundingClientRect()
|
||||||
const touchPosition = [e.changedTouches[0].pageX, e.changedTouches[0].pageY]
|
const touchPosition = [e.changedTouches[0].pageX, e.changedTouches[0].pageY]
|
||||||
const relativePosition = [
|
const relativePosition = [
|
||||||
@ -144,10 +143,11 @@ export abstract class S2ChartView<P extends SpreadSheet> extends AntVAbstractCha
|
|||||||
touchPosition[1] - canvasPosition.y
|
touchPosition[1] - canvasPosition.y
|
||||||
]
|
]
|
||||||
const shape = s2Instance.container.getShape(relativePosition[0], relativePosition[1])
|
const shape = s2Instance.container.getShape(relativePosition[0], relativePosition[1])
|
||||||
// 图片单元格点击放大图片
|
// 图片单元格,表头排序图标点击放大图片
|
||||||
if (shape.cfg?.parent.constructor.name === 'ImageCell') {
|
if (shape.cfg?.type === 'image') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const callback = () => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
if (shape) {
|
if (shape) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { isEmpty, isNumber } from 'lodash-es'
|
import { isNumber } from 'lodash-es'
|
||||||
import { DEFAULT_TITLE_STYLE } from '../editor/util/chart'
|
import { DEFAULT_TITLE_STYLE } from '../editor/util/chart'
|
||||||
import { equalsAny, includesAny } from '../editor/util/StringUtils'
|
import { equalsAny, includesAny } from '../editor/util/StringUtils'
|
||||||
import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types'
|
import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types'
|
||||||
@ -12,8 +12,7 @@ import { ElMessage } from 'element-plus-secondary'
|
|||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { useLinkStoreWithOut } from '@/store/modules/link'
|
import { useLinkStoreWithOut } from '@/store/modules/link'
|
||||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
import { Decimal } from 'decimal.js'
|
||||||
import { deepCopy } from '@/utils/utils'
|
|
||||||
|
|
||||||
const appStore = useAppStoreWithOut()
|
const appStore = useAppStoreWithOut()
|
||||||
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
||||||
@ -286,17 +285,23 @@ export function handleEmptyDataStrategy<O extends PickOptions>(chart: Chart, opt
|
|||||||
}
|
}
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
const { yAxis, xAxisExt, extStack } = chart
|
const { yAxis, xAxisExt, extStack, extBubble } = chart
|
||||||
const multiDimension = yAxis?.length >= 2 || xAxisExt?.length > 0 || extStack?.length > 0
|
const multiDimension = yAxis?.length >= 2 || xAxisExt?.length > 0 || extStack?.length > 0
|
||||||
switch (strategy) {
|
switch (strategy) {
|
||||||
case 'breakLine': {
|
case 'breakLine': {
|
||||||
if (multiDimension) {
|
|
||||||
// 多维度保持空
|
|
||||||
if (isChartMix) {
|
if (isChartMix) {
|
||||||
for (let i = 0; i < data.length; i++) {
|
if (data[0]) {
|
||||||
handleBreakLineMultiDimension(data[i] as Record<string, any>[])
|
if (xAxisExt?.length > 0 || extStack?.length > 0) {
|
||||||
|
handleBreakLineMultiDimension(data[0] as Record<string, any>[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data[1]) {
|
||||||
|
if (extBubble?.length > 0) {
|
||||||
|
handleBreakLineMultiDimension(data[1] as Record<string, any>[])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (multiDimension) {
|
||||||
handleBreakLineMultiDimension(data)
|
handleBreakLineMultiDimension(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,22 +311,27 @@ export function handleEmptyDataStrategy<O extends PickOptions>(chart: Chart, opt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'setZero': {
|
case 'setZero': {
|
||||||
|
if (isChartMix) {
|
||||||
|
if (data[0]) {
|
||||||
|
if (xAxisExt?.length > 0 || extStack?.length > 0) {
|
||||||
|
handleSetZeroMultiDimension(data[0] as Record<string, any>[])
|
||||||
|
} else {
|
||||||
|
handleSetZeroSingleDimension(data[0] as Record<string, any>[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (data[1]) {
|
||||||
|
if (extBubble?.length > 0) {
|
||||||
|
handleSetZeroMultiDimension(data[1] as Record<string, any>[], true)
|
||||||
|
} else {
|
||||||
|
handleSetZeroSingleDimension(data[1] as Record<string, any>[], true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (multiDimension) {
|
if (multiDimension) {
|
||||||
// 多维度置0
|
// 多维度置0
|
||||||
if (isChartMix) {
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
handleSetZeroMultiDimension(data[i] as Record<string, any>[])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleSetZeroMultiDimension(data)
|
handleSetZeroMultiDimension(data)
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// 单维度置0
|
// 单维度置0
|
||||||
if (isChartMix) {
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
|
||||||
handleSetZeroSingleDimension(data[i] as Record<string, any>[])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
handleSetZeroSingleDimension(data)
|
handleSetZeroSingleDimension(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,7 +377,7 @@ function handleBreakLineMultiDimension(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSetZeroMultiDimension(data: Record<string, any>[]) {
|
function handleSetZeroMultiDimension(data: Record<string, any>[], isExt = false) {
|
||||||
const dimensionInfoMap = new Map()
|
const dimensionInfoMap = new Map()
|
||||||
const subDimensionSet = new Set()
|
const subDimensionSet = new Set()
|
||||||
const quotaMap = new Map<string, { id: string }[]>()
|
const quotaMap = new Map<string, { id: string }[]>()
|
||||||
@ -375,6 +385,9 @@ function handleSetZeroMultiDimension(data: Record<string, any>[]) {
|
|||||||
const item = data[i]
|
const item = data[i]
|
||||||
if (item.value === null) {
|
if (item.value === null) {
|
||||||
item.value = 0
|
item.value = 0
|
||||||
|
if (isExt) {
|
||||||
|
item.valueExt = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const dimensionInfo = dimensionInfoMap.get(item.field)
|
const dimensionInfo = dimensionInfoMap.get(item.field)
|
||||||
if (dimensionInfo) {
|
if (dimensionInfo) {
|
||||||
@ -391,12 +404,17 @@ function handleSetZeroMultiDimension(data: Record<string, any>[]) {
|
|||||||
let subInsertIndex = 0
|
let subInsertIndex = 0
|
||||||
subDimensionSet.forEach(dimension => {
|
subDimensionSet.forEach(dimension => {
|
||||||
if (!dimensionInfo.set.has(dimension)) {
|
if (!dimensionInfo.set.has(dimension)) {
|
||||||
data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, {
|
const _temp = {
|
||||||
field,
|
field,
|
||||||
value: 0,
|
value: 0,
|
||||||
category: dimension,
|
category: dimension,
|
||||||
quotaList: quotaMap.get(dimension as string)
|
quotaList: quotaMap.get(dimension as string)
|
||||||
})
|
} as any
|
||||||
|
if (isExt) {
|
||||||
|
_temp.valueExt = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, _temp)
|
||||||
}
|
}
|
||||||
subInsertIndex++
|
subInsertIndex++
|
||||||
})
|
})
|
||||||
@ -405,10 +423,14 @@ function handleSetZeroMultiDimension(data: Record<string, any>[]) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSetZeroSingleDimension(data: Record<string, any>[]) {
|
function handleSetZeroSingleDimension(data: Record<string, any>[], isExt = false) {
|
||||||
data.forEach(item => {
|
data.forEach(item => {
|
||||||
if (item.value === null) {
|
if (item.value === null) {
|
||||||
|
if (!isExt) {
|
||||||
item.value = 0
|
item.value = 0
|
||||||
|
} else {
|
||||||
|
item.valueExt = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -525,8 +547,20 @@ const getExcelDownloadRequest = (data, type?) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const exportExcelDownload = (chart, callBack?) => {
|
function getChartExcelTitle(preFix, viewTitle) {
|
||||||
const excelName = chart.title
|
const now = new Date()
|
||||||
|
const pad = n => n.toString().padStart(2, '0')
|
||||||
|
const year = now.getFullYear()
|
||||||
|
const month = pad(now.getMonth() + 1) // 月份从 0 开始
|
||||||
|
const day = pad(now.getDate())
|
||||||
|
const hour = pad(now.getHours())
|
||||||
|
const minute = pad(now.getMinutes())
|
||||||
|
const second = pad(now.getSeconds())
|
||||||
|
return `${preFix}_${viewTitle}_${year}${month}${day}_${hour}${minute}${second}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const exportExcelDownload = (chart, preFix, callBack?) => {
|
||||||
|
const excelName = getChartExcelTitle(preFix, chart.title)
|
||||||
let request: any = {
|
let request: any = {
|
||||||
proxy: null,
|
proxy: null,
|
||||||
dvId: chart.sceneId,
|
dvId: chart.sceneId,
|
||||||
@ -589,9 +623,11 @@ export const exportExcelDownload = (chart, callBack?) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const copyString = (content: string, notify = false) => {
|
export const copyString = (content: string, notify = false) => {
|
||||||
const clipboard = navigator.clipboard || {
|
let clipboard = navigator.clipboard as Pick<Clipboard, 'writeText'>
|
||||||
|
if (!clipboard || window.top !== window.self) {
|
||||||
|
clipboard = {
|
||||||
writeText: data => {
|
writeText: data => {
|
||||||
return new Promise(resolve => {
|
return new Promise<void>(resolve => {
|
||||||
const textareaDom = document.createElement('textarea')
|
const textareaDom = document.createElement('textarea')
|
||||||
textareaDom.setAttribute('style', 'z-index: -1;position: fixed;opacity: 0;')
|
textareaDom.setAttribute('style', 'z-index: -1;position: fixed;opacity: 0;')
|
||||||
textareaDom.value = data
|
textareaDom.value = data
|
||||||
@ -603,6 +639,7 @@ export const copyString = (content: string, notify = false) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
clipboard.writeText(content).then(() => {
|
clipboard.writeText(content).then(() => {
|
||||||
if (notify) {
|
if (notify) {
|
||||||
ElMessage.success(t('commons.copy_success'))
|
ElMessage.success(t('commons.copy_success'))
|
||||||
@ -782,7 +819,7 @@ export function getColor(chart: Chart) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
export function setupSeriesColor(chart: ChartObj): ChartBasicStyle['seriesColor'] {
|
||||||
const result: ChartBasicStyle['seriesColor'] = []
|
const result: ChartBasicStyle['seriesColor'] = []
|
||||||
const seriesSet = new Set<string>()
|
const seriesSet = new Set<string>()
|
||||||
const colors = chart.customAttr.basicStyle.colors
|
const colors = chart.customAttr.basicStyle.colors
|
||||||
@ -1155,8 +1192,10 @@ export function getLineLabelColorByCondition(conditions, value, fieldId) {
|
|||||||
if (fieldConditions.length) {
|
if (fieldConditions.length) {
|
||||||
fieldConditions.some(item => {
|
fieldConditions.some(item => {
|
||||||
if (
|
if (
|
||||||
(item.term === 'lt' && value <= item.value) ||
|
(item.term === 'lt' && value < item.value) ||
|
||||||
(item.term === 'gt' && value >= item.value) ||
|
(item.term === 'le' && value <= item.value) ||
|
||||||
|
(item.term === 'gt' && value > item.value) ||
|
||||||
|
(item.term === 'ge' && value >= item.value) ||
|
||||||
(item.term === 'between' && value >= item.min && value <= item.max)
|
(item.term === 'between' && value >= item.min && value <= item.max)
|
||||||
) {
|
) {
|
||||||
color = item.color
|
color = item.color
|
||||||
@ -1210,3 +1249,27 @@ export const hexToRgba = (hex, alpha = 1) => {
|
|||||||
// 返回 RGBA 格式
|
// 返回 RGBA 格式
|
||||||
return `rgba(${r}, ${g}, ${b}, ${a})`
|
return `rgba(${r}, ${g}, ${b}, ${a})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 安全计算数值字段的总和,使用 Decimal 避免浮点数精度问题
|
||||||
|
export function safeDecimalSum(data, field) {
|
||||||
|
// 使用 reduce 累加所有行的指定字段值
|
||||||
|
return data
|
||||||
|
.reduce((acc, row) => {
|
||||||
|
// 将字段值转换为 Decimal 类型并累加到累加器
|
||||||
|
return acc.plus(new Decimal(row[field] ?? 0))
|
||||||
|
}, new Decimal(0))
|
||||||
|
.toNumber() // 最终结果转换为普通数字返回
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安全计算数值字段的平均值,使用 Decimal 避免浮点数精度问题
|
||||||
|
export function safeDecimalMean(data, field) {
|
||||||
|
// 如果数据为空,直接返回 0
|
||||||
|
if (!data.length) return 0
|
||||||
|
// 计算所有行的指定字段值的总和
|
||||||
|
const sum = data.reduce((acc, row) => {
|
||||||
|
// 将字段值转换为 Decimal 类型并累加到累加器
|
||||||
|
return acc.plus(new Decimal(row[field] ?? 0))
|
||||||
|
}, new Decimal(0))
|
||||||
|
// 将总和除以数据行数,得到平均值,并转换为普通数字返回
|
||||||
|
return sum.dividedBy(data.length).toNumber()
|
||||||
|
}
|
||||||
|
@ -14,12 +14,11 @@ import { ChartLibraryType } from '@/views/chart/components/js/panel/types'
|
|||||||
import { G2PlotChartView } from '@/views/chart/components/js/panel/types/impl/g2plot'
|
import { G2PlotChartView } from '@/views/chart/components/js/panel/types/impl/g2plot'
|
||||||
import { L7PlotChartView } from '@/views/chart/components/js/panel/types/impl/l7plot'
|
import { L7PlotChartView } from '@/views/chart/components/js/panel/types/impl/l7plot'
|
||||||
import chartViewManager from '@/views/chart/components/js/panel'
|
import chartViewManager from '@/views/chart/components/js/panel'
|
||||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
import ViewTrackBar from '@/components/visualization/ViewTrackBar.vue'
|
import ViewTrackBar from '@/components/visualization/ViewTrackBar.vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { parseJson } from '@/views/chart/components/js/util'
|
import { parseJson } from '@/views/chart/components/js/util'
|
||||||
import { defaultsDeep, cloneDeep } from 'lodash-es'
|
import { defaultsDeep, cloneDeep, concat } from 'lodash-es'
|
||||||
import ChartError from '@/views/chart/components/views/components/ChartError.vue'
|
import ChartError from '@/views/chart/components/views/components/ChartError.vue'
|
||||||
import { BASE_VIEW_CONFIG } from '../../editor/util/chart'
|
import { BASE_VIEW_CONFIG } from '../../editor/util/chart'
|
||||||
import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/utils/canvasStyle'
|
import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/utils/canvasStyle'
|
||||||
@ -28,7 +27,8 @@ import { isDashboard, trackBarStyleCheck } from '@/utils/canvasUtils'
|
|||||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||||
import { L7ChartView } from '@/views/chart/components/js/panel/types/impl/l7'
|
import { L7ChartView } from '@/views/chart/components/js/panel/types/impl/l7'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { ExportImage,Scale } from '@antv/l7'
|
import { ExportImage } from '@antv/l7'
|
||||||
|
import { configEmptyDataStyle } from '@/views/chart/components/js/panel/common/common_antv'
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const dvMainStore = dvMainStoreWithOut()
|
const dvMainStore = dvMainStoreWithOut()
|
||||||
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, embeddedCallBack, inMobile } =
|
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, embeddedCallBack, inMobile } =
|
||||||
@ -75,6 +75,11 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: 'inherit'
|
default: 'inherit'
|
||||||
|
},
|
||||||
|
active: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -89,6 +94,14 @@ const emit = defineEmits([
|
|||||||
const g2TypeSeries1 = ['bidirectional-bar']
|
const g2TypeSeries1 = ['bidirectional-bar']
|
||||||
const g2TypeSeries0 = ['bar-range']
|
const g2TypeSeries0 = ['bar-range']
|
||||||
const g2TypeTree = ['circle-packing']
|
const g2TypeTree = ['circle-packing']
|
||||||
|
const g2TypeStack = [
|
||||||
|
'bar-stack',
|
||||||
|
'bar-group-stack',
|
||||||
|
'percentage-bar-stack',
|
||||||
|
'bar-stack-horizontal',
|
||||||
|
'percentage-bar-stack-horizontal'
|
||||||
|
]
|
||||||
|
const g2TypeGroup = ['bar-group']
|
||||||
|
|
||||||
const { view, showPosition, scale, terminal, suffixId } = toRefs(props)
|
const { view, showPosition, scale, terminal, suffixId } = toRefs(props)
|
||||||
|
|
||||||
@ -132,8 +145,11 @@ const clearLinkage = () => {
|
|||||||
}
|
}
|
||||||
const reDrawView = () => {
|
const reDrawView = () => {
|
||||||
linkageActiveHistory.value = false
|
linkageActiveHistory.value = false
|
||||||
|
const slider = myChart?.chart?.getController('slider')
|
||||||
|
if (!slider) {
|
||||||
myChart?.render()
|
myChart?.render()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const linkageActivePre = () => {
|
const linkageActivePre = () => {
|
||||||
if (linkageActiveHistory.value) {
|
if (linkageActiveHistory.value) {
|
||||||
reDrawView()
|
reDrawView()
|
||||||
@ -144,43 +160,103 @@ const linkageActivePre = () => {
|
|||||||
}
|
}
|
||||||
const linkageActive = () => {
|
const linkageActive = () => {
|
||||||
linkageActiveHistory.value = true
|
linkageActiveHistory.value = true
|
||||||
|
myChart?.setState('active', () => true, false)
|
||||||
|
myChart?.setState('inactive', () => true, false)
|
||||||
|
myChart?.setState('selected', () => true, false)
|
||||||
myChart?.setState('active', param => {
|
myChart?.setState('active', param => {
|
||||||
if (Array.isArray(param)) {
|
if (Array.isArray(param)) {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
if (checkSelected(param)) {
|
return checkSelected(param)
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
myChart?.setState('inactive', param => {
|
myChart?.setState('inactive', param => {
|
||||||
if (Array.isArray(param)) {
|
if (Array.isArray(param)) {
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
if (!checkSelected(param)) {
|
return !checkSelected(param)
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
myChart?.setState('selected', param => {
|
||||||
|
if (Array.isArray(param)) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return checkSelected(param)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const checkSelected = param => {
|
const checkSelected = param => {
|
||||||
|
// 获取当前视图的所有联动字段ID
|
||||||
|
const mappingFieldIds = Array.from(
|
||||||
|
new Set(
|
||||||
|
(view.value.type.includes('chart-mix')
|
||||||
|
? concat(chartData.value?.left?.fields, chartData.value?.right?.fields)
|
||||||
|
: chartData.value?.fields
|
||||||
|
)
|
||||||
|
.map(item => item?.id)
|
||||||
|
.filter(id =>
|
||||||
|
Object.keys(nowPanelTrackInfo.value).some(
|
||||||
|
key => key.startsWith(view.value.id) && key.split('#')[1] === id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// 维度字段匹配
|
||||||
|
const [xAxis, xAxisExt, extStack] = ['xAxis', 'xAxisExt', 'extStack'].map(key =>
|
||||||
|
view.value[key].find(item => mappingFieldIds.includes(item.id))
|
||||||
|
)
|
||||||
|
// 选中字段数据
|
||||||
|
const { group, name, category } = state.linkageActiveParam
|
||||||
|
// 选中字段数据匹配
|
||||||
if (g2TypeSeries1.includes(view.value.type)) {
|
if (g2TypeSeries1.includes(view.value.type)) {
|
||||||
return state.linkageActiveParam.name === param.field
|
return name === param.field
|
||||||
} else if (g2TypeSeries0.includes(view.value.type)) {
|
} else if (g2TypeSeries0.includes(view.value.type)) {
|
||||||
return state.linkageActiveParam.category === param.category
|
return category === param.category
|
||||||
} else if (g2TypeTree.includes(view.value.type)) {
|
} else if (g2TypeTree.includes(view.value.type)) {
|
||||||
if (
|
if (param.path?.startsWith(name) || name === t('commons.all')) {
|
||||||
param.path?.startsWith(state.linkageActiveParam.name) ||
|
|
||||||
state.linkageActiveParam.name === t('commons.all')
|
|
||||||
) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return state.linkageActiveParam.name === param.name
|
return name === param.name
|
||||||
|
} else if (g2TypeGroup.includes(view.value.type)) {
|
||||||
|
const isNameMatch = name === param.name || (name === 'NO_DATA' && !param.name)
|
||||||
|
const isCategoryMatch = category === param.category
|
||||||
|
if (xAxis && xAxisExt) {
|
||||||
|
return isNameMatch && isCategoryMatch
|
||||||
|
}
|
||||||
|
if (xAxis && !xAxisExt) {
|
||||||
|
return isNameMatch
|
||||||
|
}
|
||||||
|
if (!xAxis && xAxisExt) {
|
||||||
|
return isCategoryMatch
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} else if (g2TypeStack.includes(view.value.type)) {
|
||||||
|
const isGroupMatch = group === param.group || (group === 'NO_DATA' && !param.group)
|
||||||
|
const isNameMatch = name === param.name || (name === 'NO_DATA' && !param.name)
|
||||||
|
const isCategoryMatch = category === param.category
|
||||||
|
// 全部匹配
|
||||||
|
if (xAxis && xAxisExt && extStack) {
|
||||||
|
return isNameMatch && isGroupMatch && isCategoryMatch
|
||||||
|
}
|
||||||
|
// 只匹配到维度
|
||||||
|
if (xAxis && !xAxisExt && !extStack) {
|
||||||
|
return isNameMatch
|
||||||
|
} else if (!xAxis && xAxisExt && !extStack) {
|
||||||
|
return isGroupMatch
|
||||||
|
} else if (!xAxis && !xAxisExt && extStack) {
|
||||||
|
return isCategoryMatch
|
||||||
|
} else if (xAxis && xAxisExt && !extStack) {
|
||||||
|
return isNameMatch && isGroupMatch
|
||||||
|
} else if (xAxis && !xAxisExt && extStack) {
|
||||||
|
return isNameMatch && isCategoryMatch
|
||||||
|
} else if (!xAxis && xAxisExt && extStack) {
|
||||||
|
return isGroupMatch && isCategoryMatch
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
(state.linkageActiveParam.name === param.name ||
|
(name === param.name || (name === 'NO_DATA' && !param.name)) && category === param.category
|
||||||
(state.linkageActiveParam.name === 'NO_DATA' && !param.name)) &&
|
|
||||||
state.linkageActiveParam.category === param.category
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,6 +350,8 @@ const renderG2Plot = async (chart, chartView: G2PlotChartView<any, any>) => {
|
|||||||
g2Timer && clearTimeout(g2Timer)
|
g2Timer && clearTimeout(g2Timer)
|
||||||
g2Timer = setTimeout(async () => {
|
g2Timer = setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
|
// 在这里清理掉之前图表的空dom
|
||||||
|
configEmptyDataStyle([1], containerId)
|
||||||
myChart?.destroy()
|
myChart?.destroy()
|
||||||
myChart = await chartView.drawChart({
|
myChart = await chartView.drawChart({
|
||||||
chartObj: myChart,
|
chartObj: myChart,
|
||||||
@ -295,7 +373,6 @@ const renderG2Plot = async (chart, chartView: G2PlotChartView<any, any>) => {
|
|||||||
|
|
||||||
const dynamicAreaId = ref('')
|
const dynamicAreaId = ref('')
|
||||||
const country = ref('')
|
const country = ref('')
|
||||||
const appStore = useAppStoreWithOut()
|
|
||||||
const chartContainer = ref<HTMLElement>(null)
|
const chartContainer = ref<HTMLElement>(null)
|
||||||
let scope
|
let scope
|
||||||
let mapTimer: number
|
let mapTimer: number
|
||||||
@ -332,8 +409,6 @@ const renderL7Plot = async (chart: ChartObj, chartView: L7PlotChartView<any, any
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mapL7Timer: number
|
let mapL7Timer: number
|
||||||
let scaleControl: Scale | null = null // 存储比例尺实例
|
|
||||||
|
|
||||||
const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callback) => {
|
const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callback) => {
|
||||||
mapL7Timer && clearTimeout(mapL7Timer)
|
mapL7Timer && clearTimeout(mapL7Timer)
|
||||||
mapL7Timer = setTimeout(async () => {
|
mapL7Timer = setTimeout(async () => {
|
||||||
@ -343,25 +418,12 @@ const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callb
|
|||||||
chart: chart,
|
chart: chart,
|
||||||
action
|
action
|
||||||
})
|
})
|
||||||
|
|
||||||
// 清除已有比例尺
|
|
||||||
if (scaleControl) {
|
|
||||||
myChart.getScene()?.removeControl(scaleControl)
|
|
||||||
scaleControl = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建并添加新比例尺
|
|
||||||
scaleControl = new Scale({
|
|
||||||
position: 'bottomleft',
|
|
||||||
imperial: false
|
|
||||||
})
|
|
||||||
myChart.getScene()?.addControl(scaleControl)
|
|
||||||
|
|
||||||
myChart?.render()
|
myChart?.render()
|
||||||
callback?.()
|
callback?.()
|
||||||
emit('resetLoading')
|
emit('resetLoading')
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointClickTrans = () => {
|
const pointClickTrans = () => {
|
||||||
if (embeddedCallBack.value === 'yes') {
|
if (embeddedCallBack.value === 'yes') {
|
||||||
trackClick('pointClick')
|
trackClick('pointClick')
|
||||||
@ -375,11 +437,8 @@ const actionDefault = param => {
|
|||||||
if (param.from === 'word-cloud') {
|
if (param.from === 'word-cloud') {
|
||||||
emitter.emit('word-cloud-default-data-range', param)
|
emitter.emit('word-cloud-default-data-range', param)
|
||||||
}
|
}
|
||||||
if (param.from === 'gauge') {
|
if (param.from === 'gauge' || param.from === 'liquid') {
|
||||||
emitter.emit('gauge-default-data', param)
|
emitter.emit('gauge-liquid-y-value', param)
|
||||||
}
|
|
||||||
if (param.from === 'liquid') {
|
|
||||||
emitter.emit('liquid-default-data', param)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +458,8 @@ const action = param => {
|
|||||||
// 下钻 联动 跳转
|
// 下钻 联动 跳转
|
||||||
state.linkageActiveParam = {
|
state.linkageActiveParam = {
|
||||||
category: state.pointParam.data.category ? state.pointParam.data.category : 'NO_DATA',
|
category: state.pointParam.data.category ? state.pointParam.data.category : 'NO_DATA',
|
||||||
name: state.pointParam.data.name ? state.pointParam.data.name : 'NO_DATA'
|
name: state.pointParam.data.name ? state.pointParam.data.name : 'NO_DATA',
|
||||||
|
group: state.pointParam.data.group ? state.pointParam.data.group : 'NO_DATA'
|
||||||
}
|
}
|
||||||
if (trackMenu.value.length < 2) {
|
if (trackMenu.value.length < 2) {
|
||||||
// 只有一个事件直接调用
|
// 只有一个事件直接调用
|
||||||
@ -429,7 +489,7 @@ const action = param => {
|
|||||||
state.trackBarStyle.top = trackBarY + 'px'
|
state.trackBarStyle.top = trackBarY + 'px'
|
||||||
}
|
}
|
||||||
|
|
||||||
viewTrack.value.trackButtonClick()
|
viewTrack.value.trackButtonClick(view.value.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,10 +498,28 @@ const trackClick = trackAction => {
|
|||||||
if (!param?.data?.dimensionList) {
|
if (!param?.data?.dimensionList) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let checkName = state.pointParam.data.name
|
let checkName = undefined
|
||||||
|
if (param.data.dimensionList.length > 1) {
|
||||||
|
// 分组堆叠处理 去能比较出来值的那个维度
|
||||||
|
if (view.value.type === 'bar-group-stack') {
|
||||||
|
const length = param.data.dimensionList.length
|
||||||
|
// 存在最后一个id
|
||||||
|
if (param.data.dimensionList[length - 1].id === param.data.dimensionList[length - 2].id) {
|
||||||
|
param.data.dimensionList.pop()
|
||||||
|
}
|
||||||
|
param.data.dimensionList.forEach(dimension => {
|
||||||
|
if (dimension.value === param.data.category) {
|
||||||
|
checkName = dimension.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!checkName) {
|
||||||
// 对多维度的处理 取第一个
|
// 对多维度的处理 取第一个
|
||||||
if (state.pointParam.data.dimensionList.length > 1) {
|
checkName = param.data.dimensionList[0].id
|
||||||
checkName = state.pointParam.data.dimensionList[0].id
|
}
|
||||||
|
}
|
||||||
|
if (!checkName) {
|
||||||
|
checkName = param.data.name
|
||||||
}
|
}
|
||||||
// 跳转字段处理
|
// 跳转字段处理
|
||||||
let jumpName = state.pointParam.data.name
|
let jumpName = state.pointParam.data.name
|
||||||
@ -480,7 +558,7 @@ const trackClick = trackAction => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let quotaList = state.pointParam.data.quotaList
|
let quotaList = state.pointParam.data.quotaList
|
||||||
if (['bar-range'].includes(curView.type)) {
|
if (['bar-range', 'bullet-graph'].includes(curView.type)) {
|
||||||
quotaList = state.pointParam.data.dimensionList
|
quotaList = state.pointParam.data.dimensionList
|
||||||
} else {
|
} else {
|
||||||
quotaList[0]['value'] = state.pointParam.data.value
|
quotaList[0]['value'] = state.pointParam.data.value
|
||||||
@ -535,10 +613,17 @@ const trackMenu = computed(() => {
|
|||||||
let trackMenuInfo = []
|
let trackMenuInfo = []
|
||||||
// 复用、放大状态的仪表板不进行联动、跳转和下钻的动作
|
// 复用、放大状态的仪表板不进行联动、跳转和下钻的动作
|
||||||
if (!['multiplexing', 'viewDialog'].includes(showPosition.value)) {
|
if (!['multiplexing', 'viewDialog'].includes(showPosition.value)) {
|
||||||
|
let drillFields =
|
||||||
|
curView?.drill && curView?.drillFilters?.length
|
||||||
|
? curView.drillFilters.map(item => item.fieldId)
|
||||||
|
: []
|
||||||
let linkageCount = 0
|
let linkageCount = 0
|
||||||
let jumpCount = 0
|
let jumpCount = 0
|
||||||
if (curView?.type?.includes('chart-mix')) {
|
if (curView?.type?.includes('chart-mix')) {
|
||||||
chartData.value?.left?.fields?.forEach(item => {
|
Array.of('left', 'right').forEach(side => {
|
||||||
|
chartData.value?.[side]?.fields
|
||||||
|
?.filter(item => !drillFields.includes(item.id))
|
||||||
|
.forEach(item => {
|
||||||
const sourceInfo = view.value.id + '#' + item.id
|
const sourceInfo = view.value.id + '#' + item.id
|
||||||
if (nowPanelTrackInfo.value[sourceInfo]) {
|
if (nowPanelTrackInfo.value[sourceInfo]) {
|
||||||
linkageCount++
|
linkageCount++
|
||||||
@ -547,17 +632,11 @@ const trackMenu = computed(() => {
|
|||||||
jumpCount++
|
jumpCount++
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
chartData.value?.right?.fields?.forEach(item => {
|
|
||||||
const sourceInfo = view.value.id + '#' + item.id
|
|
||||||
if (nowPanelTrackInfo.value[sourceInfo]) {
|
|
||||||
linkageCount++
|
|
||||||
}
|
|
||||||
if (nowPanelJumpInfo.value[sourceInfo]) {
|
|
||||||
jumpCount++
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
chartData.value?.fields?.forEach(item => {
|
chartData.value?.fields
|
||||||
|
?.filter(item => !drillFields.includes(item.id))
|
||||||
|
.forEach(item => {
|
||||||
const sourceInfo = view.value.id + '#' + item.id
|
const sourceInfo = view.value.id + '#' + item.id
|
||||||
if (nowPanelTrackInfo.value[sourceInfo]) {
|
if (nowPanelTrackInfo.value[sourceInfo]) {
|
||||||
linkageCount++
|
linkageCount++
|
||||||
@ -615,7 +694,7 @@ const canvas2Picture = (pictureData, online) => {
|
|||||||
mapDom.appendChild(imgDom)
|
mapDom.appendChild(imgDom)
|
||||||
}
|
}
|
||||||
const preparePicture = id => {
|
const preparePicture = id => {
|
||||||
if (id !== curView.id) {
|
if (id !== curView?.id) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const chartView = chartViewManager.getChartView(curView.render, curView.type)
|
const chartView = chartViewManager.getChartView(curView.render, curView.type)
|
||||||
@ -639,7 +718,7 @@ const preparePicture = id => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const unPreparePicture = id => {
|
const unPreparePicture = id => {
|
||||||
if (id !== curView.id) {
|
if (id !== curView?.id) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const chartView = chartViewManager.getChartView(curView.render, curView.type)
|
const chartView = chartViewManager.getChartView(curView.render, curView.type)
|
||||||
@ -667,6 +746,7 @@ defineExpose({
|
|||||||
trackMenu,
|
trackMenu,
|
||||||
clearLinkage
|
clearLinkage
|
||||||
})
|
})
|
||||||
|
let intersectionObserver
|
||||||
let resizeObserver
|
let resizeObserver
|
||||||
const TOLERANCE = 0.01
|
const TOLERANCE = 0.01
|
||||||
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map', 'flow-map', 'heat-map']
|
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map', 'flow-map', 'heat-map']
|
||||||
@ -691,13 +771,32 @@ onMounted(() => {
|
|||||||
preSize[1] = size.blockSize
|
preSize[1] = size.blockSize
|
||||||
})
|
})
|
||||||
resizeObserver.observe(containerDom)
|
resizeObserver.observe(containerDom)
|
||||||
|
intersectionObserver = new IntersectionObserver(([entry]) => {
|
||||||
|
if (RESIZE_MONITOR_CHARTS.includes(view.value.type)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (entry.intersectionRatio <= 0) {
|
||||||
|
myChart?.emit('tooltip:hidden')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
intersectionObserver.observe(containerDom)
|
||||||
useEmitt({ name: 'l7-prepare-picture', callback: preparePicture })
|
useEmitt({ name: 'l7-prepare-picture', callback: preparePicture })
|
||||||
useEmitt({ name: 'l7-unprepare-picture', callback: unPreparePicture })
|
useEmitt({ name: 'l7-unprepare-picture', callback: unPreparePicture })
|
||||||
})
|
})
|
||||||
|
const MAP_CHARTS = ['map', 'bubble-map', 'flow-map', 'heat-map', 'symbolic-map']
|
||||||
|
const onWheel = (e: WheelEvent) => {
|
||||||
|
if (!MAP_CHARTS.includes(view.value.type)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!props.active) {
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
try {
|
try {
|
||||||
myChart?.destroy()
|
myChart?.destroy()
|
||||||
resizeObserver?.disconnect()
|
resizeObserver?.disconnect()
|
||||||
|
intersectionObserver?.disconnect()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e)
|
console.warn(e)
|
||||||
}
|
}
|
||||||
@ -715,7 +814,13 @@ onBeforeUnmount(() => {
|
|||||||
:style="state.trackBarStyle"
|
:style="state.trackBarStyle"
|
||||||
@trackClick="trackClick"
|
@trackClick="trackClick"
|
||||||
/>
|
/>
|
||||||
<div v-if="!isError" ref="chartContainer" class="canvas-content" :id="containerId"></div>
|
<div
|
||||||
|
@wheel.capture="onWheel"
|
||||||
|
v-if="!isError"
|
||||||
|
ref="chartContainer"
|
||||||
|
class="canvas-content"
|
||||||
|
:id="containerId"
|
||||||
|
></div>
|
||||||
<chart-error v-else :err-msg="errMsg" />
|
<chart-error v-else :err-msg="errMsg" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -16,7 +16,6 @@ import {
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
import { getData } from '@/api/chart'
|
import { getData } from '@/api/chart'
|
||||||
import chartViewManager from '@/views/chart/components/js/panel'
|
import chartViewManager from '@/views/chart/components/js/panel'
|
||||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
|
||||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||||
import ViewTrackBar from '@/components/visualization/ViewTrackBar.vue'
|
import ViewTrackBar from '@/components/visualization/ViewTrackBar.vue'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
@ -125,6 +124,7 @@ const state = reactive({
|
|||||||
imgEnlarge: false,
|
imgEnlarge: false,
|
||||||
imgSrc: ''
|
imgSrc: ''
|
||||||
})
|
})
|
||||||
|
const PAGE_CHARTS = ['table-info', 'table-normal']
|
||||||
// 图表数据不用全响应式
|
// 图表数据不用全响应式
|
||||||
let chartData = shallowRef<Partial<Chart['data']>>({
|
let chartData = shallowRef<Partial<Chart['data']>>({
|
||||||
fields: []
|
fields: []
|
||||||
@ -133,17 +133,20 @@ let chartData = shallowRef<Partial<Chart['data']>>({
|
|||||||
const containerId = 'container-' + showPosition.value + '-' + view.value.id + '-' + suffixId.value
|
const containerId = 'container-' + showPosition.value + '-' + view.value.id + '-' + suffixId.value
|
||||||
const viewTrack = ref(null)
|
const viewTrack = ref(null)
|
||||||
|
|
||||||
const calcData = (view: Chart, callback, resetPageInfo = true) => {
|
const calcData = (viewInfo: Chart, callback, resetPageInfo = true) => {
|
||||||
if (view.customAttr.basicStyle.tablePageStyle === 'general') {
|
if (viewInfo.customAttr.basicStyle.tablePageStyle === 'general') {
|
||||||
if (state.currentPageSize !== 0) {
|
if (state.currentPageSize !== 0) {
|
||||||
view.chartExtRequest.pageSize = state.currentPageSize
|
viewInfo.chartExtRequest.pageSize = state.currentPageSize
|
||||||
|
state.pageInfo.pageSize = state.currentPageSize
|
||||||
|
} else {
|
||||||
|
viewInfo.chartExtRequest.pageSize = state.pageInfo.pageSize
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
delete view.chartExtRequest.pageSize
|
delete viewInfo.chartExtRequest?.pageSize
|
||||||
}
|
}
|
||||||
if (view.tableId || view['dataFrom'] === 'template') {
|
if (viewInfo.tableId || viewInfo['dataFrom'] === 'template') {
|
||||||
isError.value = false
|
isError.value = false
|
||||||
const v = JSON.parse(JSON.stringify(view))
|
const v = JSON.parse(JSON.stringify(viewInfo))
|
||||||
getData(v)
|
getData(v)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.code && res.code !== 0) {
|
if (res.code && res.code !== 0) {
|
||||||
@ -152,7 +155,7 @@ const calcData = (view: Chart, callback, resetPageInfo = true) => {
|
|||||||
} else {
|
} else {
|
||||||
chartData.value = res?.data as Partial<Chart['data']>
|
chartData.value = res?.data as Partial<Chart['data']>
|
||||||
state.totalItems = res?.totalItems
|
state.totalItems = res?.totalItems
|
||||||
dvMainStore.setViewDataDetails(view.id, res)
|
dvMainStore.setViewDataDetails(viewInfo.id, res)
|
||||||
emit('onDrillFilters', res?.drillFilters)
|
emit('onDrillFilters', res?.drillFilters)
|
||||||
renderChart(res as unknown as Chart, resetPageInfo)
|
renderChart(res as unknown as Chart, resetPageInfo)
|
||||||
}
|
}
|
||||||
@ -223,7 +226,7 @@ const renderChart = (viewInfo: Chart, resetPageInfo: boolean) => {
|
|||||||
nextTick(() => debounceRender(resetPageInfo))
|
nextTick(() => debounceRender(resetPageInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
const debounceRender = debounce(resetPageInfo => {
|
const debounceRender = debounce(() => {
|
||||||
myChart?.facet?.timer?.stop()
|
myChart?.facet?.timer?.stop()
|
||||||
myChart?.facet?.cancelScrollFrame()
|
myChart?.facet?.cancelScrollFrame()
|
||||||
myChart?.destroy()
|
myChart?.destroy()
|
||||||
@ -248,19 +251,13 @@ const debounceRender = debounce(resetPageInfo => {
|
|||||||
|
|
||||||
const setupPage = (chart: ChartObj, resetPageInfo?: boolean) => {
|
const setupPage = (chart: ChartObj, resetPageInfo?: boolean) => {
|
||||||
const customAttr = chart.customAttr
|
const customAttr = chart.customAttr
|
||||||
if (chart.type !== 'table-info' || customAttr.basicStyle.tablePageMode !== 'page') {
|
if (!PAGE_CHARTS.includes(chart.type) || customAttr.basicStyle.tablePageMode !== 'page') {
|
||||||
state.showPage = false
|
state.showPage = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const pageInfo = state.pageInfo
|
const pageInfo = state.pageInfo
|
||||||
state.pageStyle = customAttr.basicStyle.tablePageStyle
|
state.pageStyle = customAttr.basicStyle.tablePageStyle
|
||||||
if (state.pageStyle === 'general') {
|
if (state.pageStyle !== 'general') {
|
||||||
if (state.currentPageSize === 0) {
|
|
||||||
state.currentPageSize = pageInfo.pageSize
|
|
||||||
} else {
|
|
||||||
pageInfo.pageSize = state.currentPageSize
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pageInfo.pageSize = customAttr.basicStyle.tablePageSize ?? 20
|
pageInfo.pageSize = customAttr.basicStyle.tablePageSize ?? 20
|
||||||
}
|
}
|
||||||
if (state.totalItems > state.pageInfo.pageSize || state.pageStyle === 'general') {
|
if (state.totalItems > state.pageInfo.pageSize || state.pageStyle === 'general') {
|
||||||
@ -272,6 +269,7 @@ const setupPage = (chart: ChartObj, resetPageInfo?: boolean) => {
|
|||||||
if (resetPageInfo) {
|
if (resetPageInfo) {
|
||||||
state.pageInfo.currentPage = 1
|
state.pageInfo.currentPage = 1
|
||||||
}
|
}
|
||||||
|
dvMainStore.setViewPageInfo(chart.id, state.pageInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
const mouseMove = () => {
|
const mouseMove = () => {
|
||||||
@ -293,7 +291,8 @@ const initScroll = () => {
|
|||||||
myChart &&
|
myChart &&
|
||||||
senior?.scrollCfg?.open &&
|
senior?.scrollCfg?.open &&
|
||||||
chartData.value.tableRow?.length &&
|
chartData.value.tableRow?.length &&
|
||||||
(view.value.type === 'table-normal' || (view.value.type === 'table-info' && !state.showPage))
|
PAGE_CHARTS.includes(props.view.type) &&
|
||||||
|
!state.showPage
|
||||||
) {
|
) {
|
||||||
// 防止多次渲染
|
// 防止多次渲染
|
||||||
myChart.facet.timer?.stop()
|
myChart.facet.timer?.stop()
|
||||||
@ -337,7 +336,7 @@ const initScroll = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const showPage = computed(() => {
|
const showPage = computed(() => {
|
||||||
if (view.value.type !== 'table-info') {
|
if (!PAGE_CHARTS.includes(view.value.type)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return state.showPage
|
return state.showPage
|
||||||
@ -355,6 +354,7 @@ const handleCurrentChange = pageNum => {
|
|||||||
const handlePageSizeChange = pageSize => {
|
const handlePageSizeChange = pageSize => {
|
||||||
if (state.pageStyle === 'general') {
|
if (state.pageStyle === 'general') {
|
||||||
state.currentPageSize = pageSize
|
state.currentPageSize = pageSize
|
||||||
|
emitter.emit('set-page-size', pageSize)
|
||||||
}
|
}
|
||||||
let extReq = { pageSize: pageSize }
|
let extReq = { pageSize: pageSize }
|
||||||
if (chartExtRequest.value) {
|
if (chartExtRequest.value) {
|
||||||
@ -401,10 +401,9 @@ const action = param => {
|
|||||||
state.trackBarStyle.top = barStyleTemp.top + 'px'
|
state.trackBarStyle.top = barStyleTemp.top + 'px'
|
||||||
}
|
}
|
||||||
|
|
||||||
viewTrack.value.trackButtonClick()
|
viewTrack.value.trackButtonClick(view.value.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const appStore = useAppStoreWithOut()
|
|
||||||
|
|
||||||
const trackClick = trackAction => {
|
const trackClick = trackAction => {
|
||||||
const param = state.pointParam
|
const param = state.pointParam
|
||||||
@ -681,12 +680,6 @@ const autoStyle = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const autoHeightStyle = computed(() => {
|
|
||||||
return {
|
|
||||||
height: 20 * scale.value + 8 + 'px'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const tabStyle = computed(() => [
|
const tabStyle = computed(() => [
|
||||||
{ '--de-pager-color': canvasStyleData.value.component.seniorStyleSetting?.pagerColor }
|
{ '--de-pager-color': canvasStyleData.value.component.seniorStyleSetting?.pagerColor }
|
||||||
])
|
])
|
||||||
@ -743,7 +736,7 @@ const tablePageClass = computed(() => {
|
|||||||
v-else
|
v-else
|
||||||
class="table-page-content"
|
class="table-page-content"
|
||||||
layout="prev, pager, next, sizes, jumper"
|
layout="prev, pager, next, sizes, jumper"
|
||||||
v-model:page-size="state.currentPageSize"
|
v-model:page-size="state.pageInfo.pageSize"
|
||||||
v-model:current-page="state.pageInfo.currentPage"
|
v-model:current-page="state.pageInfo.currentPage"
|
||||||
:pager-count="5"
|
:pager-count="5"
|
||||||
:total="state.pageInfo.total"
|
:total="state.pageInfo.total"
|
||||||
|
@ -4,7 +4,7 @@ import { ref } from 'vue'
|
|||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
errMsg: {
|
errMsg: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user