forked from github/dataease
feat(图表-流向地图): 支持配置起止点名称以及样式配置优化
This commit is contained in:
parent
fa3b7403e1
commit
ab950c57e7
@ -529,34 +529,6 @@ declare interface ChartMiscAttr {
|
||||
* 地图倾角
|
||||
*/
|
||||
mapPitch: number
|
||||
/**
|
||||
* 地图线条类型
|
||||
*/
|
||||
mapLineType: string
|
||||
/**
|
||||
* 地图线条宽度
|
||||
*/
|
||||
mapLineWidth: number
|
||||
/**
|
||||
* 流向地图动画
|
||||
*/
|
||||
mapLineAnimate?: boolean
|
||||
/**
|
||||
* 流向地图动画间隔
|
||||
*/
|
||||
mapLineAnimateDuration: number
|
||||
/**
|
||||
* 地图线条渐变
|
||||
*/
|
||||
mapLineGradient: boolean
|
||||
/**
|
||||
* 地图线条渐变起始颜色
|
||||
*/
|
||||
mapLineSourceColor: string
|
||||
/**
|
||||
* 地图线条渐变结束颜色
|
||||
*/
|
||||
mapLineTargetColor: string
|
||||
/**
|
||||
* 指标/文本卡值字体
|
||||
*/
|
||||
@ -653,6 +625,54 @@ declare interface ChartMiscAttr {
|
||||
* 显示图例个数
|
||||
*/
|
||||
mapLegendNumber: number
|
||||
/**
|
||||
* 流向地图配置
|
||||
*/
|
||||
flowMapConfig: {
|
||||
lineConfig: {
|
||||
/**
|
||||
* 地图线条类型
|
||||
*/
|
||||
mapLineType: string
|
||||
/**
|
||||
* 地图线条宽度
|
||||
*/
|
||||
mapLineWidth: number
|
||||
/**
|
||||
* 流向地图动画
|
||||
*/
|
||||
mapLineAnimate?: boolean
|
||||
/**
|
||||
* 流向地图动画间隔
|
||||
*/
|
||||
mapLineAnimateDuration: number
|
||||
/**
|
||||
* 地图线条渐变
|
||||
*/
|
||||
mapLineGradient: boolean
|
||||
/**
|
||||
* 地图线条渐变起始颜色
|
||||
*/
|
||||
mapLineSourceColor: string
|
||||
/**
|
||||
* 地图线条渐变结束颜色
|
||||
*/
|
||||
mapLineTargetColor: string
|
||||
alpha: number
|
||||
}
|
||||
pointConfig: {
|
||||
text: {
|
||||
color: string
|
||||
fontSize: number
|
||||
}
|
||||
point: {
|
||||
color: string
|
||||
size: number
|
||||
animate: boolean
|
||||
speed: number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 动态极值配置
|
||||
|
@ -65,6 +65,8 @@ declare interface Chart {
|
||||
* 针对不是序列字段的图表,通过获取分类字段的值作为序列字段
|
||||
*/
|
||||
seriesFieldObjs?: any[]
|
||||
flowMapStartName?: Axis[]
|
||||
flowMapEndName?: Axis[]
|
||||
}
|
||||
declare type CustomAttr = DeepPartial<ChartAttr> | JSONString<DeepPartial<ChartAttr>>
|
||||
declare type CustomStyle = DeepPartial<ChartStyle> | JSONString<DeepPartial<ChartStyle>>
|
||||
|
@ -25,6 +25,8 @@ declare type EditorProperty =
|
||||
| 'indicator-name-selector'
|
||||
| 'quadrant-selector'
|
||||
| 'map-symbolic-selector'
|
||||
| 'flow-map-line-selector'
|
||||
| 'flow-map-point-selector'
|
||||
declare type EditorPropertyInner = {
|
||||
[key in EditorProperty]?: string[]
|
||||
}
|
||||
@ -50,6 +52,9 @@ declare type AxisType =
|
||||
| 'extLabel'
|
||||
| 'extTooltip'
|
||||
| 'area'
|
||||
| 'flowMapStartName'
|
||||
| 'flowMapEndName'
|
||||
| 'flowMapColor'
|
||||
/**
|
||||
* 轴配置
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@ import LegendSelector from '@/views/chart/components/editor/editor-style/compone
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import CollapseSwitchItem from '@/components/collapse-switch-item/src/CollapseSwitchItem.vue'
|
||||
import { ElCollapseItem } from 'element-plus-secondary'
|
||||
import { ElCollapse, ElCollapseItem } from 'element-plus-secondary'
|
||||
import BasicStyleSelector from '@/views/chart/components/editor/editor-style/components/BasicStyleSelector.vue'
|
||||
import ComponentPosition from '@/components/visualization/common/ComponentPosition.vue'
|
||||
import BackgroundOverallCommon from '@/components/visualization/component-background/BackgroundOverallCommon.vue'
|
||||
@ -23,6 +23,8 @@ import MiscStyleSelector from '@/views/chart/components/editor/editor-style/comp
|
||||
import IndicatorValueSelector from '@/views/chart/components/editor/editor-style/components/IndicatorValueSelector.vue'
|
||||
import IndicatorNameSelector from '@/views/chart/components/editor/editor-style/components/IndicatorNameSelector.vue'
|
||||
import QuadrantSelector from '@/views/chart/components/editor/editor-style/components/QuadrantSelector.vue'
|
||||
import FlowMapLineSelector from '@/views/chart/components/editor/editor-style/components/FlowMapLineSelector.vue'
|
||||
import FlowMapPointSelector from '@/views/chart/components/editor/editor-style/components/FlowMapPointSelector.vue'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { dvInfo } = storeToRefs(dvMainStore)
|
||||
@ -103,7 +105,9 @@ const emit = defineEmits([
|
||||
'onExtTooltipChange',
|
||||
'onIndicatorChange',
|
||||
'onIndicatorNameChange',
|
||||
'onChangeQuadrantForm'
|
||||
'onChangeQuadrantForm',
|
||||
'onChangeFlowMapLineForm',
|
||||
'onChangeFlowMapPointForm'
|
||||
])
|
||||
|
||||
const indicatorValueRef = ref()
|
||||
@ -189,6 +193,12 @@ const onExtTooltipChange = val => {
|
||||
const onChangeQuadrantForm = val => {
|
||||
emit('onChangeQuadrantForm', val)
|
||||
}
|
||||
const onChangeFlowMapLineForm = val => {
|
||||
emit('onChangeFlowMapLineForm', val)
|
||||
}
|
||||
const onChangeFlowMapPointForm = val => {
|
||||
emit('onChangeFlowMapPointForm', val)
|
||||
}
|
||||
watch(
|
||||
() => props.chart.id,
|
||||
() => {
|
||||
@ -436,6 +446,35 @@ watch(
|
||||
@onChangeQuadrantForm="onChangeQuadrantForm"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item
|
||||
:effect="themes"
|
||||
name="flowMapLineSelector"
|
||||
title="线条"
|
||||
v-if="showProperties('flow-map-line-selector')"
|
||||
>
|
||||
<flow-map-line-selector
|
||||
class="attr-selector"
|
||||
:property-inner="propertyInnerAll['flow-map-line-selector']"
|
||||
:themes="themes"
|
||||
:chart="chart"
|
||||
@onChangeFlowMapLineForm="onChangeFlowMapLineForm"
|
||||
@onBasicStyleChange="onBasicStyleChange"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item
|
||||
:effect="themes"
|
||||
name="flowMapPointSelector"
|
||||
title="标注"
|
||||
v-if="showProperties('flow-map-point-selector')"
|
||||
>
|
||||
<flow-map-point-selector
|
||||
class="attr-selector"
|
||||
:property-inner="propertyInnerAll['flow-map-point-selector']"
|
||||
:themes="themes"
|
||||
:chart="chart"
|
||||
@onChangeFlowMapPointForm="onChangeFlowMapPointForm"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
|
||||
<el-collapse v-model="state.styleActiveNames" class="style-collapse">
|
||||
|
@ -55,16 +55,6 @@ watch(
|
||||
)
|
||||
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
||||
const changeBasicStyle = (prop?: string, requestData = false) => {
|
||||
const mapLineColorStyle = prop?.split('@')
|
||||
if (mapLineColorStyle.length === 2) {
|
||||
if (mapLineColorStyle[1].toLowerCase() === 'SourceColor'.toLowerCase()) {
|
||||
state.basicStyleForm.colors[0] = state.miscForm.mapLineSourceColor
|
||||
}
|
||||
if (mapLineColorStyle[1].toLowerCase() === 'TargetColor'.toLowerCase()) {
|
||||
state.basicStyleForm.colors[1] = state.miscForm.mapLineTargetColor
|
||||
}
|
||||
changeMisc(state.basicStyleForm.colors[0] + state.basicStyleForm.colors[1])
|
||||
}
|
||||
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData }, prop)
|
||||
}
|
||||
const onAlphaChange = v => {
|
||||
@ -92,10 +82,6 @@ const init = () => {
|
||||
configCompat(basicStyle)
|
||||
state.basicStyleForm = defaultsDeep(basicStyle, cloneDeep(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
||||
state.miscForm = defaultsDeep(miscStyle, cloneDeep(DEFAULT_MISC)) as ChartMiscAttr
|
||||
if (props.chart.type === 'flow-map') {
|
||||
state.miscForm.mapLineSourceColor = state.basicStyleForm.colors[0]
|
||||
state.miscForm.mapLineTargetColor = state.basicStyleForm.colors[1]
|
||||
}
|
||||
if (!state.customColor) {
|
||||
state.customColor = state.basicStyleForm.colors[0]
|
||||
state.colorIndex = 0
|
||||
@ -222,12 +208,6 @@ const heatMapTypeOptions = [
|
||||
{ name: t('chart.heatmap3D'), value: 'heatmap3D' }
|
||||
]
|
||||
|
||||
const flowLineTypeOptions = [
|
||||
{ name: t('chart.map_line_type_line'), value: 'line' },
|
||||
{ name: t('chart.map_line_type_arc'), value: 'arc' },
|
||||
{ name: t('chart.map_line_type_arc_3d'), value: 'arc3d' }
|
||||
]
|
||||
|
||||
const mapSymbolOptions = [
|
||||
{ name: t('chart.line_symbol_circle'), value: 'circle' },
|
||||
{ name: t('chart.line_symbol_rect'), value: 'square' },
|
||||
@ -410,190 +390,6 @@ onMounted(() => {
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-flow-style" v-if="showProperty('mapLineStyle')">
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item
|
||||
:label="t('chart.line') + t('chart.map_line_type')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-select
|
||||
:effect="themes"
|
||||
v-model="state.miscForm.mapLineType"
|
||||
@change="changeMisc('mapLineType')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in flowLineTypeOptions"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.map_line_width') }}
|
||||
</label>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="1"
|
||||
:max="10"
|
||||
v-model="state.miscForm.mapLineWidth"
|
||||
@change="changeMisc('mapLineWidth')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.miscForm.mapLineGradient"
|
||||
:predefine="predefineColors"
|
||||
@change="changeMisc('mapLineGradient')"
|
||||
>
|
||||
{{ t('chart.line') + t('chart.map_line_linear') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div v-if="state.miscForm.mapLineGradient">
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col :span="13">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.map_line_color_source_color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.miscForm.mapLineSourceColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeBasicStyle('mapLine@SourceColor')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.map_line_color_target_color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.miscForm.mapLineTargetColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeBasicStyle('mapLine@TargetColor')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div v-if="!state.miscForm.mapLineGradient">
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col>
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.miscForm.mapLineSourceColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeBasicStyle('mapLine@SourceColor')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.not_alpha') }}
|
||||
</label>
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col :span="13">
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.alpha"
|
||||
@change="changeBasicStyle('alpha')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" style="padding-top: 2px">
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-input
|
||||
type="number"
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.alpha"
|
||||
:min="0"
|
||||
:max="100"
|
||||
class="basic-input-number"
|
||||
:controls="false"
|
||||
@change="onAlphaChange"
|
||||
>
|
||||
<template #suffix> % </template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.miscForm.mapLineAnimate"
|
||||
:predefine="predefineColors"
|
||||
@change="changeMisc('mapLineAnimate')"
|
||||
>
|
||||
{{ t('chart.line') + t('chart.map_line_animate') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="alpha-setting" v-if="state.miscForm.mapLineAnimate">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.map_line_animate_duration') }}
|
||||
</label>
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="0"
|
||||
:max="20"
|
||||
v-model="state.miscForm.mapLineAnimateDuration"
|
||||
@change="changeMisc('mapLineAnimateDuration')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alpha-setting" v-if="showProperty('heatMapStyle')">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.heatMapIntensity') }}
|
||||
|
@ -0,0 +1,326 @@
|
||||
<script lang="tsx" setup>
|
||||
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import {
|
||||
COLOR_PANEL,
|
||||
DEFAULT_BASIC_STYLE,
|
||||
DEFAULT_MISC
|
||||
} from '@/views/chart/components/editor/util/chart'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const props = defineProps({
|
||||
chart: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
themes: {
|
||||
type: String as PropType<EditorTheme>,
|
||||
default: 'dark'
|
||||
},
|
||||
propertyInner: {
|
||||
type: Array<string>
|
||||
}
|
||||
})
|
||||
const predefineColors = COLOR_PANEL
|
||||
const flowLineTypeOptions = [
|
||||
{ name: t('chart.map_line_type_line'), value: 'line' },
|
||||
{ name: t('chart.map_line_type_arc'), value: 'arc' },
|
||||
{ name: t('chart.map_line_type_arc_3d'), value: 'arc3d' }
|
||||
]
|
||||
const state = reactive({
|
||||
lineForm: {
|
||||
...JSON.parse(JSON.stringify(DEFAULT_MISC.flowMapConfig.lineConfig))
|
||||
},
|
||||
basicStyleForm: {
|
||||
...JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE))
|
||||
}
|
||||
})
|
||||
const toolTip = computed(() => {
|
||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
||||
})
|
||||
const emit = defineEmits(['onChangeFlowMapLineForm', 'onBasicStyleChange'])
|
||||
|
||||
watch(
|
||||
() => props.chart.customAttr.misc.flowMapConfig.lineConfig,
|
||||
() => {
|
||||
init()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const changeStyle = () => {
|
||||
state.basicStyleForm.colors[0] = state.lineForm.mapLineSourceColor
|
||||
state.basicStyleForm.colors[1] = state.lineForm.mapLineTargetColor
|
||||
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData: false }, 'colors')
|
||||
emit('onChangeFlowMapLineForm', state.lineForm)
|
||||
}
|
||||
const onAlphaChange = v => {
|
||||
const _v = parseInt(v)
|
||||
if (_v >= 0 && _v <= 100) {
|
||||
state.lineForm.alpha = _v
|
||||
} else if (_v < 0) {
|
||||
state.lineForm.alpha = 0
|
||||
} else if (_v > 100) {
|
||||
state.lineForm.alpha = 100
|
||||
} else {
|
||||
const lineConfig = cloneDeep(props.chart.customAttr.misc.flowMapConfig.lineConfig)
|
||||
const oldForm = defaultsDeep(
|
||||
lineConfig,
|
||||
cloneDeep(DEFAULT_MISC.flowMapConfig)
|
||||
) as ChartBasicStyle
|
||||
state.lineForm.alpha = oldForm.alpha
|
||||
}
|
||||
changeStyle()
|
||||
}
|
||||
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)
|
||||
}
|
||||
const basicStyle = customAttr.basicStyle
|
||||
state.basicStyleForm = defaultsDeep(
|
||||
basicStyle,
|
||||
cloneDeep(DEFAULT_BASIC_STYLE)
|
||||
) as ChartBasicStyle
|
||||
configCompat(basicStyle)
|
||||
if (customAttr.misc.flowMapConfig.lineConfig) {
|
||||
state.lineForm = customAttr.misc.flowMapConfig.lineConfig
|
||||
state.lineForm.mapLineSourceColor = state.basicStyleForm.colors[0]
|
||||
state.lineForm.mapLineTargetColor = state.basicStyleForm.colors[1]
|
||||
} else {
|
||||
// 新增图表
|
||||
state.lineForm = {
|
||||
...JSON.parse(JSON.stringify(DEFAULT_MISC.flowMapConfig.lineConfig))
|
||||
}
|
||||
changeStyle()
|
||||
}
|
||||
}
|
||||
}
|
||||
const configCompat = (basicStyle: ChartBasicStyle) => {
|
||||
// 悬浮改为图例和缩放按钮
|
||||
if (basicStyle.suspension === false && basicStyle.showZoom === undefined) {
|
||||
basicStyle.showZoom = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form ref="lineForm" :model="state.lineForm" size="small" label-position="top">
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item
|
||||
:label="t('chart.line') + t('chart.map_line_type')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-select :effect="themes" v-model="state.lineForm.mapLineType" @change="changeStyle()">
|
||||
<el-option
|
||||
v-for="item in flowLineTypeOptions"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.map_line_width') }}
|
||||
</label>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="1"
|
||||
:max="10"
|
||||
v-model="state.lineForm.mapLineWidth"
|
||||
@change="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.lineForm.mapLineGradient"
|
||||
:predefine="predefineColors"
|
||||
@change="changeStyle()"
|
||||
>
|
||||
{{ t('chart.line') + t('chart.map_line_linear') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div v-if="state.lineForm.mapLineGradient">
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col :span="13">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.map_line_color_source_color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.lineForm.mapLineSourceColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="13">
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
:label="t('chart.map_line_color_target_color')"
|
||||
>
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.lineForm.mapLineTargetColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div v-if="!state.lineForm.mapLineGradient">
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" :label="t('chart.color')">
|
||||
<el-color-picker
|
||||
is-custom
|
||||
class="color-picker-style"
|
||||
v-model="state.lineForm.mapLineSourceColor"
|
||||
:persistent="false"
|
||||
:effect="themes"
|
||||
:trigger-width="108"
|
||||
:predefine="predefineColors"
|
||||
@change="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.not_alpha') }}
|
||||
</label>
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col :span="13">
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider :effect="themes" v-model="state.lineForm.alpha" @change="changeStyle()" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11" style="padding-top: 2px">
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-input
|
||||
type="number"
|
||||
:effect="themes"
|
||||
v-model="state.lineForm.alpha"
|
||||
:min="0"
|
||||
:max="100"
|
||||
class="basic-input-number"
|
||||
:controls="false"
|
||||
@change="onAlphaChange"
|
||||
>
|
||||
<template #suffix> % </template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-checkbox
|
||||
size="small"
|
||||
:effect="themes"
|
||||
v-model="state.lineForm.mapLineAnimate"
|
||||
:predefine="predefineColors"
|
||||
@change="changeStyle()"
|
||||
>
|
||||
{{ t('chart.line') + t('chart.map_line_animate') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="alpha-setting" v-if="state.lineForm.mapLineAnimate">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }">
|
||||
{{ t('chart.map_line_animate_duration') }}
|
||||
</label>
|
||||
<el-row style="flex: 1" :gutter="8">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="0"
|
||||
:max="20"
|
||||
v-model="state.lineForm.mapLineAnimateDuration"
|
||||
@change="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ed-input .ed-select__prefix--light) {
|
||||
padding-right: 6px;
|
||||
}
|
||||
.alpha-setting {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.alpha-slider {
|
||||
padding: 4px 8px;
|
||||
:deep(.ed-slider__button-wrapper) {
|
||||
--ed-slider-button-wrapper-size: 36px;
|
||||
--ed-slider-button-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.alpha-label {
|
||||
padding-right: 8px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
display: inline-flex;
|
||||
align-items: flex-start;
|
||||
|
||||
min-width: 56px;
|
||||
|
||||
&.dark {
|
||||
color: #a6a6a6;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,210 @@
|
||||
<script lang="tsx" setup>
|
||||
import { computed, onMounted, PropType, reactive, watch } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import {
|
||||
COLOR_PANEL,
|
||||
DEFAULT_BASIC_STYLE,
|
||||
DEFAULT_MISC
|
||||
} from '@/views/chart/components/editor/util/chart'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||
import { ElSpace } from 'element-plus-secondary'
|
||||
|
||||
const { t } = useI18n()
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const props = defineProps({
|
||||
chart: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
themes: {
|
||||
type: String as PropType<EditorTheme>,
|
||||
default: 'dark'
|
||||
},
|
||||
propertyInner: {
|
||||
type: Array<string>
|
||||
}
|
||||
})
|
||||
const predefineColors = COLOR_PANEL
|
||||
const fontSizeList = computed(() => {
|
||||
const arr = []
|
||||
for (let i = 10; i <= 40; i = i + 2) {
|
||||
arr.push({
|
||||
name: i + '',
|
||||
value: i
|
||||
})
|
||||
}
|
||||
return arr
|
||||
})
|
||||
const state = reactive({
|
||||
pointForm: {
|
||||
...JSON.parse(JSON.stringify(DEFAULT_MISC.flowMapConfig.pointConfig))
|
||||
}
|
||||
})
|
||||
const toolTip = computed(() => {
|
||||
return props.themes === 'dark' ? 'ndark' : 'dark'
|
||||
})
|
||||
const emit = defineEmits(['onChangeFlowMapPointForm'])
|
||||
|
||||
watch(
|
||||
() => props.chart.customAttr.misc.flowMapConfig.pointConfig,
|
||||
() => {
|
||||
init()
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const changeStyle = () => {
|
||||
emit('onChangeFlowMapPointForm', state.pointForm)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
if (customAttr.misc.flowMapConfig.lineConfig) {
|
||||
state.pointForm = customAttr.misc.flowMapConfig.pointConfig
|
||||
} else {
|
||||
// 新增图表
|
||||
state.pointForm = {
|
||||
...JSON.parse(JSON.stringify(DEFAULT_MISC.flowMapConfig.pointConfig))
|
||||
}
|
||||
changeStyle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const showProperty = prop => props.propertyInner?.includes(prop)
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form ref="pointForm" :model="state.pointForm" size="small" label-position="top">
|
||||
<el-space>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes" :label="t('chart.text')">
|
||||
<el-color-picker
|
||||
:effect="themes"
|
||||
v-model="state.pointForm.text.color"
|
||||
class="color-picker-style"
|
||||
:predefine="predefineColors"
|
||||
@change="changeStyle()"
|
||||
is-custom
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<template #label> </template>
|
||||
<el-tooltip content="字号" :effect="toolTip" placement="top">
|
||||
<el-select
|
||||
size="small"
|
||||
style="width: 108px"
|
||||
:effect="themes"
|
||||
v-model.number="state.pointForm.text.fontSize"
|
||||
:placeholder="t('chart.text_fontsize')"
|
||||
@change="changeStyle()"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in fontSizeList"
|
||||
:key="option.value"
|
||||
:label="option.name"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</el-space>
|
||||
<div class="alpha-setting">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }"> 标注点大小 </label>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="0"
|
||||
:max="5"
|
||||
v-model="state.pointForm.point.size"
|
||||
@change="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="alpha-setting">
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item" :class="'form-item-' + themes">
|
||||
<el-checkbox
|
||||
:effect="themes"
|
||||
@change="changeStyle()"
|
||||
v-model="state.pointForm.point.animate"
|
||||
>
|
||||
标注点动画
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col>
|
||||
<div class="alpha-setting" v-if="state.pointForm.point.animate">
|
||||
<label class="alpha-label" :class="{ dark: 'dark' === themes }"> 闪烁频率 </label>
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item class="form-item alpha-slider" :class="'form-item-' + themes">
|
||||
<el-slider
|
||||
:effect="themes"
|
||||
:min="1"
|
||||
:max="5"
|
||||
v-model="state.pointForm.point.speed"
|
||||
@change="changeStyle()"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ed-input .ed-select__prefix--light) {
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.alpha-setting {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
.alpha-slider {
|
||||
padding: 4px 8px;
|
||||
|
||||
:deep(.ed-slider__button-wrapper) {
|
||||
--ed-slider-button-wrapper-size: 36px;
|
||||
--ed-slider-button-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.alpha-label {
|
||||
padding-right: 8px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
display: inline-flex;
|
||||
align-items: flex-start;
|
||||
|
||||
min-width: 56px;
|
||||
|
||||
&.dark {
|
||||
color: #a6a6a6;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -396,6 +396,10 @@ const dimensionItemRemove = item => {
|
||||
view.value.yAxisExt.splice(item.index, 1)
|
||||
} else if (item.removeType === 'xAxisExtRight') {
|
||||
view.value.extBubble.splice(item.index, 1)
|
||||
} else if (item.removeType === 'flowMapStartName') {
|
||||
view.value.flowMapStartName.splice(item.index, 1)
|
||||
} else if (item.removeType === 'flowMapEndName') {
|
||||
view.value.flowMapEndName.splice(item.index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -494,6 +498,20 @@ const onExtCustomRightSort = item => {
|
||||
customSort()
|
||||
}
|
||||
|
||||
const onCustomFlowMapStartNameSort = item => {
|
||||
recordSnapshotInfo('render')
|
||||
state.customSortField = view.value.flowMapStartName[item.index]
|
||||
customSortAxis.value = 'flowMapStartName'
|
||||
customSort()
|
||||
}
|
||||
|
||||
const onCustomFlowMapEndNameSort = item => {
|
||||
recordSnapshotInfo('render')
|
||||
state.customSortField = view.value.flowMapEndName[item.index]
|
||||
customSortAxis.value = 'flowMapEndName'
|
||||
customSort()
|
||||
}
|
||||
|
||||
const onMove = e => {
|
||||
recordSnapshotInfo('calcData')
|
||||
state.moveId = e.draggedContext.element.id
|
||||
@ -759,6 +777,14 @@ const addDrill = e => {
|
||||
dragRemoveAggField(view.value.drillFields, e)
|
||||
}
|
||||
|
||||
const addFlowMapStartName = e => {
|
||||
addAxis(e, 'flowMapStartName')
|
||||
}
|
||||
|
||||
const addFlowMapEndName = e => {
|
||||
addAxis(e, 'flowMapEndName')
|
||||
}
|
||||
|
||||
const onAxisChange = (e, axis: AxisType) => {
|
||||
if (e.removed) {
|
||||
const { element } = e.removed
|
||||
@ -1045,6 +1071,14 @@ const onChangeQuadrantForm = val => {
|
||||
view.value.customAttr.quadrant = val
|
||||
renderChart(view.value)
|
||||
}
|
||||
const onChangeFlowMapLineForm = val => {
|
||||
view.value.customAttr.misc.flowMapConfig.lineConfig = val
|
||||
renderChart(view.value)
|
||||
}
|
||||
const onChangeFlowMapPointForm = val => {
|
||||
view.value.customAttr.misc.flowMapConfig.pointConfig = val
|
||||
renderChart(view.value)
|
||||
}
|
||||
|
||||
const showRename = val => {
|
||||
recordSnapshotInfo('render')
|
||||
@ -1069,6 +1103,8 @@ const removeItems = (
|
||||
| 'extBubble'
|
||||
| 'customFilter'
|
||||
| 'drillFields'
|
||||
| 'flowMapStartName'
|
||||
| 'flowMapEndName'
|
||||
) => {
|
||||
recordSnapshotInfo('calcData')
|
||||
let axis = []
|
||||
@ -1098,6 +1134,12 @@ const removeItems = (
|
||||
case 'drillFields':
|
||||
axis = view.value.drillFields?.splice(0)
|
||||
break
|
||||
case 'flowMapStartName':
|
||||
axis = view.value.flowMapStartName?.splice(0)
|
||||
break
|
||||
case 'flowMapEndName':
|
||||
axis = view.value.flowMapEndName?.splice(0)
|
||||
break
|
||||
}
|
||||
axis?.length && emitter.emit('removeAxis', { axisType: _type, axis, editType: 'remove' })
|
||||
}
|
||||
@ -1141,6 +1183,15 @@ const saveRename = ref => {
|
||||
break
|
||||
case 'extTooltip':
|
||||
view.value.extTooltip[index].chartShowName = chartShowName
|
||||
case 'flowMapStartName':
|
||||
axisType = 'flowMapStartName'
|
||||
axis = view.value.flowMapStartName[index]
|
||||
view.value.flowMapStartName[index].chartShowName = chartShowName
|
||||
break
|
||||
case 'flowMapEndName':
|
||||
axisType = 'flowMapEndName'
|
||||
axis = view.value.flowMapEndName[index]
|
||||
view.value.flowMapEndName[index].chartShowName = chartShowName
|
||||
break
|
||||
default:
|
||||
break
|
||||
@ -1870,6 +1921,122 @@ const deleteChartFieldItem = id => {
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!--flowMapStartName-->
|
||||
<el-row v-if="showAxis('flowMapStartName')" class="padding-lr drag-data">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.flowMapStartName.name }}
|
||||
</span>
|
||||
<el-tooltip
|
||||
:effect="toolTip"
|
||||
placement="top"
|
||||
:content="t('common.delete')"
|
||||
>
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('flowMapStartName')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
class="qw"
|
||||
@drop="$event => drop($event, 'flowMapStartName')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<draggable
|
||||
:list="view.flowMapStartName"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addFlowMapStartName"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<dimension-item
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
:themes="props.themes"
|
||||
type="flowMapStartName"
|
||||
@onDimensionItemChange="dimensionItemChange"
|
||||
@onDimensionItemRemove="dimensionItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@onCustomSort="onCustomFlowMapStartNameSort"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :themes="themes" :drag-list="view.flowMapStartName" />
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!--flowMapEndName-->
|
||||
<el-row v-if="showAxis('flowMapEndName')" class="padding-lr drag-data">
|
||||
<div class="form-draggable-title">
|
||||
<span>
|
||||
{{ chartViewInstance.axisConfig.flowMapEndName.name }}
|
||||
</span>
|
||||
<el-tooltip
|
||||
:effect="toolTip"
|
||||
placement="top"
|
||||
:content="t('common.delete')"
|
||||
>
|
||||
<el-icon
|
||||
class="remove-icon"
|
||||
:class="{ 'remove-icon--dark': themes === 'dark' }"
|
||||
size="14px"
|
||||
@click="removeItems('flowMapEndName')"
|
||||
>
|
||||
<Icon class-name="inner-class" name="icon_delete-trash_outlined" />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div
|
||||
class="qw"
|
||||
@drop="$event => drop($event, 'flowMapEndName')"
|
||||
@dragenter="dragEnter"
|
||||
@dragover="$event => dragOver($event)"
|
||||
>
|
||||
<draggable
|
||||
:list="view.flowMapEndName"
|
||||
:move="onMove"
|
||||
item-key="id"
|
||||
group="drag"
|
||||
animation="300"
|
||||
class="drag-block-style"
|
||||
:class="{ dark: themes === 'dark' }"
|
||||
@add="addFlowMapEndName"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<dimension-item
|
||||
:dimension-data="state.dimension"
|
||||
:quota-data="state.quota"
|
||||
:chart="view"
|
||||
:item="element"
|
||||
:index="index"
|
||||
:themes="props.themes"
|
||||
type="flowMapEndName"
|
||||
@onDimensionItemChange="dimensionItemChange"
|
||||
@onDimensionItemRemove="dimensionItemRemove"
|
||||
@onNameEdit="showRename"
|
||||
@onCustomSort="onCustomFlowMapEndNameSort"
|
||||
@valueFormatter="valueFormatter"
|
||||
/>
|
||||
</template>
|
||||
</draggable>
|
||||
<drag-placeholder :themes="themes" :drag-list="view.flowMapEndName" />
|
||||
</div>
|
||||
</el-row>
|
||||
|
||||
<!--extStack-->
|
||||
<el-row v-if="showAxis('extStack')" class="padding-lr drag-data">
|
||||
<div class="form-draggable-title">
|
||||
@ -2599,6 +2766,8 @@ const deleteChartFieldItem = id => {
|
||||
@onChangeMiscStyleForm="onChangeMiscStyleForm"
|
||||
@onExtTooltipChange="onExtTooltipChange"
|
||||
@onChangeQuadrantForm="onChangeQuadrantForm"
|
||||
@onChangeFlowMapLineForm="onChangeFlowMapLineForm"
|
||||
@onChangeFlowMapPointForm="onChangeFlowMapPointForm"
|
||||
/>
|
||||
</template>
|
||||
</el-scrollbar>
|
||||
|
@ -29,9 +29,14 @@ export const DEFAULT_COLOR_CASE: DeepPartial<ChartAttr> = {
|
||||
zoomBackground: '#fff'
|
||||
},
|
||||
misc: {
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#146C94',
|
||||
mapLineTargetColor: '#576CBC',
|
||||
flowMapConfig: {
|
||||
lineConfig: {
|
||||
mapLineAnimate: true,
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#146C94',
|
||||
mapLineTargetColor: '#576CBC'
|
||||
}
|
||||
},
|
||||
nameFontColor: '#000000',
|
||||
valueFontColor: '#5470c6'
|
||||
},
|
||||
@ -72,9 +77,14 @@ export const DEFAULT_COLOR_CASE_LIGHT: DeepPartial<ChartAttr> = {
|
||||
zoomBackground: '#fff'
|
||||
},
|
||||
misc: {
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#146C94',
|
||||
mapLineTargetColor: '#576CBC',
|
||||
flowMapConfig: {
|
||||
lineConfig: {
|
||||
mapLineAnimate: true,
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#146C94',
|
||||
mapLineTargetColor: '#576CBC'
|
||||
}
|
||||
},
|
||||
nameFontColor: '#000000',
|
||||
valueFontColor: '#5470c6'
|
||||
},
|
||||
@ -115,9 +125,13 @@ export const DEFAULT_COLOR_CASE_DARK: DeepPartial<ChartAttr> = {
|
||||
zoomBackground: '#000'
|
||||
},
|
||||
misc: {
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#2F58CD',
|
||||
mapLineTargetColor: '#3795BD',
|
||||
flowMapConfig: {
|
||||
lineConfig: {
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#146C94',
|
||||
mapLineTargetColor: '#576CBC'
|
||||
}
|
||||
},
|
||||
nameFontColor: '#ffffff',
|
||||
valueFontColor: '#5470c6'
|
||||
},
|
||||
@ -255,18 +269,36 @@ export const DEFAULT_MISC: ChartMiscAttr = {
|
||||
hPosition: 'center',
|
||||
vPosition: 'center',
|
||||
mapPitch: 0,
|
||||
mapLineType: 'arc',
|
||||
mapLineWidth: 1,
|
||||
mapLineAnimateDuration: 3,
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#146C94',
|
||||
mapLineTargetColor: '#576CBC',
|
||||
wordSizeRange: [8, 32],
|
||||
wordSpacing: 6,
|
||||
mapAutoLegend: true,
|
||||
mapLegendMax: 0,
|
||||
mapLegendMin: 0,
|
||||
mapLegendNumber: 9
|
||||
mapLegendNumber: 9,
|
||||
flowMapConfig: {
|
||||
lineConfig: {
|
||||
mapLineAnimate: true,
|
||||
mapLineType: 'arc',
|
||||
mapLineWidth: 1,
|
||||
mapLineAnimateDuration: 3,
|
||||
mapLineGradient: false,
|
||||
mapLineSourceColor: '#146C94',
|
||||
mapLineTargetColor: '#576CBC',
|
||||
alpha: 100
|
||||
},
|
||||
pointConfig: {
|
||||
text: {
|
||||
color: '#146C94',
|
||||
fontSize: 10
|
||||
},
|
||||
point: {
|
||||
color: 'red',
|
||||
size: 4,
|
||||
animate: false,
|
||||
speed: 0.01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const DEFAULT_MARK = {
|
||||
@ -1541,7 +1573,9 @@ export const BASE_VIEW_CONFIG = {
|
||||
threshold: DEFAULT_THRESHOLD,
|
||||
scrollCfg: DEFAULT_SCROLL,
|
||||
areaMapping: {}
|
||||
}
|
||||
},
|
||||
flowMapStartName: [],
|
||||
flowMapEndName: []
|
||||
}
|
||||
|
||||
export function getScaleValue(propValue, scale) {
|
||||
|
@ -11,6 +11,7 @@ import { deepCopy } from '@/utils/utils'
|
||||
import { GaodeMap } from '@antv/l7-maps'
|
||||
import { Scene } from '@antv/l7-scene'
|
||||
import { LineLayer } from '@antv/l7-layers'
|
||||
import { PointLayer } from '@antv/l7-layers'
|
||||
import { queryMapKeyApi } from '@/api/setting/sysParameter'
|
||||
import { mapRendered, mapRendering } from '@/views/chart/components/js/panel/common/common_antv'
|
||||
const { t } = useI18n()
|
||||
@ -22,13 +23,15 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
properties: EditorProperty[] = [
|
||||
'background-overall-component',
|
||||
'basic-style-selector',
|
||||
'title-selector'
|
||||
'title-selector',
|
||||
'flow-map-line-selector',
|
||||
'flow-map-point-selector'
|
||||
]
|
||||
propertyInner: EditorPropertyInner = {
|
||||
...MAP_EDITOR_PROPERTY_INNER,
|
||||
'basic-style-selector': ['mapBaseStyle', 'mapLineStyle', 'zoom']
|
||||
}
|
||||
axis: AxisType[] = ['xAxis', 'xAxisExt', 'filter']
|
||||
axis: AxisType[] = ['xAxis', 'xAxisExt', 'filter', 'flowMapStartName', 'flowMapEndName', 'yAxis']
|
||||
axisConfig: AxisConfig = {
|
||||
xAxis: {
|
||||
name: `起点经纬度 / ${t('chart.dimension')}`,
|
||||
@ -39,6 +42,21 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
name: `终点经纬度 / ${t('chart.dimension')}`,
|
||||
type: 'd',
|
||||
limit: 2
|
||||
},
|
||||
flowMapStartName: {
|
||||
name: `起点名称 / ${t('chart.dimension')}`,
|
||||
type: 'd',
|
||||
limit: 1
|
||||
},
|
||||
flowMapEndName: {
|
||||
name: `终点名称 / ${t('chart.dimension')}`,
|
||||
type: 'd',
|
||||
limit: 1
|
||||
},
|
||||
yAxis: {
|
||||
name: `线条粗细 / ${t('chart.quota')}`,
|
||||
type: 'q',
|
||||
limit: 1
|
||||
}
|
||||
}
|
||||
constructor() {
|
||||
@ -50,19 +68,6 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
const xAxis = deepCopy(chart.xAxis)
|
||||
const xAxisExt = deepCopy(chart.xAxisExt)
|
||||
const { basicStyle, misc } = deepCopy(parseJson(chart.customAttr))
|
||||
const flowLineStyle = {
|
||||
type: misc.mapLineType,
|
||||
size: misc.mapLineType === 'line' ? misc.mapLineWidth / 2 : misc.mapLineWidth,
|
||||
animate: misc.mapLineAnimate,
|
||||
animateDuration: misc.mapLineAnimateDuration,
|
||||
gradient: misc.mapLineGradient,
|
||||
sourceColor: misc.mapLineSourceColor,
|
||||
targetColor: misc.mapLineTargetColor,
|
||||
alpha: basicStyle.alpha
|
||||
}
|
||||
const colorsWithAlpha = basicStyle.colors.map(color => hexColorToRGBA(color, basicStyle.alpha))
|
||||
flowLineStyle.sourceColor = colorsWithAlpha[0]
|
||||
flowLineStyle.targetColor = colorsWithAlpha[1]
|
||||
|
||||
const mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
|
||||
const key = await this.getMapKey()
|
||||
@ -84,6 +89,48 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
if (xAxis?.length < 2 || xAxisExt?.length < 2) {
|
||||
return new L7Wrapper(scene, undefined)
|
||||
}
|
||||
const configList = []
|
||||
configList.push(this.lineConfig(chart, xAxis, xAxisExt, basicStyle, misc))
|
||||
this.startAndEndNameConfig(chart, xAxis, xAxisExt, misc, configList)
|
||||
this.pointConfig(chart, xAxis, xAxisExt, misc, configList)
|
||||
configList[0].once('inited', () => {
|
||||
mapRendered(container)
|
||||
})
|
||||
this.configZoomButton(chart, scene)
|
||||
return new L7Wrapper(scene, configList)
|
||||
}
|
||||
|
||||
lineConfig = (chart, xAxis, xAxisExt, basicStyle, misc) => {
|
||||
const flowLineStyle = {
|
||||
type: misc.flowMapConfig.lineConfig.mapLineType,
|
||||
size:
|
||||
misc.flowMapConfig.lineConfig.mapLineType === 'line'
|
||||
? misc.flowMapConfig.lineConfig.mapLineWidth / 2
|
||||
: misc.flowMapConfig.lineConfig.mapLineWidth,
|
||||
animate: misc.flowMapConfig.lineConfig.mapLineAnimate,
|
||||
animateDuration: misc.flowMapConfig.lineConfig.mapLineAnimateDuration,
|
||||
gradient: misc.flowMapConfig.lineConfig.mapLineGradient,
|
||||
sourceColor: misc.flowMapConfig.lineConfig.mapLineSourceColor,
|
||||
targetColor: misc.flowMapConfig.lineConfig.mapLineTargetColor,
|
||||
alpha: misc.flowMapConfig.lineConfig.alpha
|
||||
}
|
||||
const colorsWithAlpha = basicStyle.colors.map(color =>
|
||||
hexColorToRGBA(color, misc.flowMapConfig.lineConfig.alpha)
|
||||
)
|
||||
flowLineStyle.sourceColor = colorsWithAlpha[0]
|
||||
flowLineStyle.targetColor = colorsWithAlpha[1]
|
||||
// 线条粗细
|
||||
let lineWidthField = null
|
||||
const yAxis = deepCopy(chart.yAxis)
|
||||
if (yAxis.length > 0) {
|
||||
lineWidthField = yAxis[0].dataeaseName
|
||||
}
|
||||
// 线条颜色
|
||||
let lineColorField = null
|
||||
const yAxisExt = deepCopy(chart.yAxisExt)
|
||||
if (yAxisExt.length > 0) {
|
||||
lineColorField = yAxisExt[0].dataeaseName
|
||||
}
|
||||
const config: L7Config = new LineLayer({
|
||||
name: 'line',
|
||||
blend: 'normal',
|
||||
@ -106,24 +153,167 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
interval: 1,
|
||||
trailLength: 1
|
||||
})
|
||||
if (flowLineStyle.gradient) {
|
||||
|
||||
if (lineWidthField) {
|
||||
config.size(lineWidthField, [1, 10])
|
||||
}
|
||||
if (lineColorField) {
|
||||
config.style({
|
||||
sourceColor: flowLineStyle.sourceColor,
|
||||
targetColor: flowLineStyle.targetColor,
|
||||
opacity: flowLineStyle.alpha / 100
|
||||
})
|
||||
config.color(lineColorField)
|
||||
} else {
|
||||
config
|
||||
.style({
|
||||
if (flowLineStyle.gradient) {
|
||||
config.style({
|
||||
sourceColor: flowLineStyle.sourceColor,
|
||||
targetColor: flowLineStyle.targetColor,
|
||||
opacity: flowLineStyle.alpha / 100
|
||||
})
|
||||
.color(flowLineStyle.sourceColor)
|
||||
} else {
|
||||
config
|
||||
.style({
|
||||
opacity: flowLineStyle.alpha / 100
|
||||
})
|
||||
.color(flowLineStyle.sourceColor)
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
startAndEndNameConfig = (chart, xAxis, xAxisExt, misc, configList) => {
|
||||
const flowMapStartName = deepCopy(chart.flowMapStartName)
|
||||
const flowMapEndName = deepCopy(chart.flowMapEndName)
|
||||
const textColor = misc.flowMapConfig.pointConfig.text.color
|
||||
const textFontSize = misc.flowMapConfig.pointConfig.text.fontSize
|
||||
const has = new Map()
|
||||
if (flowMapStartName?.length > 0) {
|
||||
const startTextLayer = new PointLayer()
|
||||
.source(chart.data?.tableRow, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxis[0].dataeaseName,
|
||||
y: xAxis[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.shape(flowMapStartName[0].dataeaseName, args => {
|
||||
if (has.has('from-' + args)) {
|
||||
return ''
|
||||
}
|
||||
has.set('from-' + args, args)
|
||||
return args
|
||||
})
|
||||
.size(textFontSize)
|
||||
.color(textColor)
|
||||
.style({
|
||||
textAnchor: 'top', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
spacing: 2, // 字符间距
|
||||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||
textAllowOverlap: true
|
||||
})
|
||||
configList.push(startTextLayer)
|
||||
}
|
||||
if (flowMapEndName?.length > 0) {
|
||||
const endTextLayer = new PointLayer()
|
||||
.source(chart.data?.tableRow, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxisExt[0].dataeaseName,
|
||||
y: xAxisExt[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.shape(flowMapEndName[0].dataeaseName, args => {
|
||||
if (has.has('from-' + args) || has.has('to-' + args)) {
|
||||
return ''
|
||||
}
|
||||
has.set('to-' + args, args)
|
||||
return args
|
||||
})
|
||||
.size(textFontSize)
|
||||
.color(textColor)
|
||||
.style({
|
||||
textAnchor: 'top', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
spacing: 2, // 字符间距
|
||||
padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||
textAllowOverlap: true
|
||||
})
|
||||
configList.push(endTextLayer)
|
||||
}
|
||||
}
|
||||
|
||||
pointConfig = (chart, xAxis, xAxisExt, misc, configList) => {
|
||||
const color = misc.flowMapConfig.pointConfig.text.color
|
||||
const size = misc.flowMapConfig.pointConfig.point.size
|
||||
const animate = misc.flowMapConfig.pointConfig.point.animate
|
||||
const speed = misc.flowMapConfig.pointConfig.point.speed
|
||||
const fromDefaultPointLayer = new PointLayer({ zIndex: -1 })
|
||||
.source(chart.data?.tableRow, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxis[0].dataeaseName,
|
||||
y: xAxis[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.size(size)
|
||||
.color(color)
|
||||
.style({
|
||||
blur: 0.6
|
||||
})
|
||||
configList.push(fromDefaultPointLayer)
|
||||
const fromAnimatePointLayer = new PointLayer({ zIndex: -1 })
|
||||
.source(chart.data?.tableRow, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxis[0].dataeaseName,
|
||||
y: xAxis[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.size(20)
|
||||
.color(color)
|
||||
.animate({
|
||||
enable: true,
|
||||
speed: speed,
|
||||
rings: 0.01
|
||||
})
|
||||
const toDefaultPointLayer = new PointLayer({ zIndex: -1 })
|
||||
.source(chart.data?.tableRow, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxisExt[0].dataeaseName,
|
||||
y: xAxisExt[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.size(size)
|
||||
.color(color)
|
||||
.style({
|
||||
blur: 0.6
|
||||
})
|
||||
configList.push(toDefaultPointLayer)
|
||||
const toAnimatePointLayer = new PointLayer({ zIndex: -1 })
|
||||
.source(chart.data?.tableRow, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxisExt[0].dataeaseName,
|
||||
y: xAxisExt[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.size(20)
|
||||
.color(color)
|
||||
.animate({
|
||||
enable: true,
|
||||
speed: speed,
|
||||
rings: 0.01
|
||||
})
|
||||
if (animate) {
|
||||
configList.push(fromAnimatePointLayer)
|
||||
configList.push(toAnimatePointLayer)
|
||||
}
|
||||
config.once('inited', () => {
|
||||
mapRendered(container)
|
||||
})
|
||||
this.configZoomButton(chart, scene)
|
||||
return new L7Wrapper(scene, config)
|
||||
}
|
||||
|
||||
getMapKey = async () => {
|
||||
@ -135,7 +325,7 @@ export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
}
|
||||
|
||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||
chart.customAttr.misc.mapLineAnimate = true
|
||||
chart.customAttr.misc.flowMapConfig.lineConfig.mapLineAnimate = true
|
||||
return chart
|
||||
}
|
||||
|
||||
|
@ -208,4 +208,14 @@ public class ChartViewBaseDTO implements Serializable {
|
||||
*/
|
||||
private Boolean aggregate;
|
||||
|
||||
/**
|
||||
* 流向地图起点名称
|
||||
*/
|
||||
private List<ChartViewFieldDTO> flowMapStartName;
|
||||
|
||||
/**
|
||||
* 流向地图终点名称
|
||||
*/
|
||||
private List<ChartViewFieldDTO> flowMapEndName;
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user