forked from github/dataease
feat(图表): 新增流向地图
This commit is contained in:
parent
af9629747e
commit
8cc1aab59f
11
core/core-frontend/src/assets/svg/bar-bidirectional-dark.svg
Normal file
11
core/core-frontend/src/assets/svg/bar-bidirectional-dark.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M41 2.00391V53.0016V54.0016H38V2.00391H41Z" fill="#434343"/>
|
||||
<path d="M4.5 50C4.22386 50 4 49.7761 4 49.5L4 42.5C4 42.2239 4.22386 42 4.5 42H35.5C35.7761 42 36 42.2239 36 42.5V49.5C36 49.7761 35.7761 50 35.5 50H4.5Z" fill="#00D6B9"/>
|
||||
<path d="M12.5 38C12.2239 38 12 37.7761 12 37.5V30.5C12 30.2239 12.2239 30 12.5 30H35.5C35.7761 30 36 30.2239 36 30.5V37.5C36 37.7761 35.7761 38 35.5 38H12.5Z" fill="#00D6B9"/>
|
||||
<path d="M43.5 14C43.2239 14 43 13.7761 43 13.5V6.5C43 6.22386 43.2239 6 43.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L43.5 14Z" fill="#3370FF"/>
|
||||
<path d="M43.5 26C43.2239 26 43 25.7761 43 25.5V18.5C43 18.2239 43.2239 18 43.5 18H62.5C62.7761 18 63 18.2239 63 18.5V25.5C63 25.7761 62.7761 26 62.5 26H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 38C43.2239 38 43 37.7761 43 37.5V30.5C43 30.2239 43.2239 30 43.5 30H57.5C57.7761 30 58 30.2239 58 30.5V37.5C58 37.7761 57.7761 38 57.5 38H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 50C43.2239 50 43 49.7761 43 49.5V42.5C43 42.2239 43.2239 42 43.5 42H75.5C75.7761 42 76 42.2239 76 42.5V49.5C76 49.7761 75.7761 50 75.5 50H43.5Z" fill="#3370FF"/>
|
||||
<path d="M16.5 26C16.2239 26 16 25.7761 16 25.5V18.5C16 18.2239 16.2239 18 16.5 18H35.5C35.7761 18 36 18.2239 36 18.5V25.5C36 25.7761 35.7761 26 35.5 26H16.5Z" fill="#00D6B9"/>
|
||||
<path d="M8.5 14C8.22386 14 8 13.7761 8 13.5V6.5C8 6.22386 8.22386 6 8.5 6L35.5 6C35.7761 6 36 6.22386 36 6.5V13.5C36 13.7761 35.7761 14 35.5 14L8.5 14Z" fill="#00D6B9"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
11
core/core-frontend/src/assets/svg/bar-bidirectional.svg
Normal file
11
core/core-frontend/src/assets/svg/bar-bidirectional.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M41 2.00391V53.0016V54.0016H38V2.00391H41Z" fill="#DEE0E3"/>
|
||||
<path d="M4.5 50C4.22386 50 4 49.7761 4 49.5L4 42.5C4 42.2239 4.22386 42 4.5 42H35.5C35.7761 42 36 42.2239 36 42.5V49.5C36 49.7761 35.7761 50 35.5 50H4.5Z" fill="#00D6B9"/>
|
||||
<path d="M12.5 38C12.2239 38 12 37.7761 12 37.5V30.5C12 30.2239 12.2239 30 12.5 30H35.5C35.7761 30 36 30.2239 36 30.5V37.5C36 37.7761 35.7761 38 35.5 38H12.5Z" fill="#00D6B9"/>
|
||||
<path d="M43.5 14C43.2239 14 43 13.7761 43 13.5V6.5C43 6.22386 43.2239 6 43.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L43.5 14Z" fill="#3370FF"/>
|
||||
<path d="M43.5 26C43.2239 26 43 25.7761 43 25.5V18.5C43 18.2239 43.2239 18 43.5 18H62.5C62.7761 18 63 18.2239 63 18.5V25.5C63 25.7761 62.7761 26 62.5 26H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 38C43.2239 38 43 37.7761 43 37.5V30.5C43 30.2239 43.2239 30 43.5 30H57.5C57.7761 30 58 30.2239 58 30.5V37.5C58 37.7761 57.7761 38 57.5 38H43.5Z" fill="#3370FF"/>
|
||||
<path d="M43.5 50C43.2239 50 43 49.7761 43 49.5V42.5C43 42.2239 43.2239 42 43.5 42H75.5C75.7761 42 76 42.2239 76 42.5V49.5C76 49.7761 75.7761 50 75.5 50H43.5Z" fill="#3370FF"/>
|
||||
<path d="M16.5 26C16.2239 26 16 25.7761 16 25.5V18.5C16 18.2239 16.2239 18 16.5 18H35.5C35.7761 18 36 18.2239 36 18.5V25.5C36 25.7761 35.7761 26 35.5 26H16.5Z" fill="#00D6B9"/>
|
||||
<path d="M8.5 14C8.22386 14 8 13.7761 8 13.5V6.5C8 6.22386 8.22386 6 8.5 6L35.5 6C35.7761 6 36 6.22386 36 6.5V13.5C36 13.7761 35.7761 14 35.5 14L8.5 14Z" fill="#00D6B9"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
11
core/core-frontend/src/assets/svg/bar-progress-dark.svg
Normal file
11
core/core-frontend/src/assets/svg/bar-progress-dark.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2.00391V53.0016V54.0016H4V2.00391H7Z" fill="#434343"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L9.5 14Z" fill="#434343"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H71.5C71.7761 18 72 18.2239 72 18.5V25.5C72 25.7761 71.7761 26 71.5 26L9.5 26Z" fill="#434343"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H71.5C71.7761 30 72 30.2239 72 30.5V37.5C72 37.7761 71.7761 38 71.5 38H9.5Z" fill="#434343"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H71.5C71.7761 42 72 42.2239 72 42.5V49.5C72 49.7761 71.7761 50 71.5 50H9.5Z" fill="#434343"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L59.5 6C59.7761 6 60 6.22386 60 6.5V13.5C60 13.7761 59.7761 14 59.5 14L9.5 14Z" fill="#3370FF"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H46.5C46.7761 18 47 18.2239 47 18.5V25.5C47 25.7761 46.7761 26 46.5 26H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H37.5C37.7761 30 38 30.2239 38 30.5V37.5C38 37.7761 37.7761 38 37.5 38H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H21.5C21.7761 42 22 42.2239 22 42.5V49.5C22 49.7761 21.7761 50 21.5 50H9.5Z" fill="#3370FF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
11
core/core-frontend/src/assets/svg/bar-progress.svg
Normal file
11
core/core-frontend/src/assets/svg/bar-progress.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7 2.00391V53.0016V54.0016H4V2.00391H7Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L71.5 6C71.7761 6 72 6.22386 72 6.5V13.5C72 13.7761 71.7761 14 71.5 14L9.5 14Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H71.5C71.7761 18 72 18.2239 72 18.5V25.5C72 25.7761 71.7761 26 71.5 26L9.5 26Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H71.5C71.7761 30 72 30.2239 72 30.5V37.5C72 37.7761 71.7761 38 71.5 38H9.5Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H71.5C71.7761 42 72 42.2239 72 42.5V49.5C72 49.7761 71.7761 50 71.5 50H9.5Z" fill="#DEE0E3"/>
|
||||
<path d="M9.5 14C9.22386 14 9 13.7761 9 13.5V6.5C9 6.22386 9.22386 6 9.5 6L59.5 6C59.7761 6 60 6.22386 60 6.5V13.5C60 13.7761 59.7761 14 59.5 14L9.5 14Z" fill="#3370FF"/>
|
||||
<path d="M9.5 26C9.22386 26 9 25.7761 9 25.5V18.5C9 18.2239 9.22386 18 9.5 18H46.5C46.7761 18 47 18.2239 47 18.5V25.5C47 25.7761 46.7761 26 46.5 26H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 38C9.22386 38 9 37.7761 9 37.5V30.5C9 30.2239 9.22386 30 9.5 30H37.5C37.7761 30 38 30.2239 38 30.5V37.5C38 37.7761 37.7761 38 37.5 38H9.5Z" fill="#3370FF"/>
|
||||
<path d="M9.5 50C9.22386 50 9 49.7761 9 49.5V42.5C9 42.2239 9.22386 42 9.5 42H21.5C21.7761 42 22 42.2239 22 42.5V49.5C22 49.7761 21.7761 50 21.5 50H9.5Z" fill="#3370FF"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
69
core/core-frontend/src/assets/svg/flow-map-origin.svg
Normal file
69
core/core-frontend/src/assets/svg/flow-map-origin.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 739 KiB |
79
core/core-frontend/src/assets/svg/flow-map.svg
Normal file
79
core/core-frontend/src/assets/svg/flow-map.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 742 KiB |
@ -294,7 +294,7 @@ const active = computed(() => {
|
||||
})
|
||||
|
||||
const boardMoveActive = computed(() => {
|
||||
const CHARTS = ['map', 'bubble-map', 'table-info', 'table-normal', 'table-pivot']
|
||||
const CHARTS = ['flow-map', 'map', 'bubble-map', 'table-info', 'table-normal', 'table-pivot']
|
||||
return CHARTS.includes(element.value.innerType)
|
||||
})
|
||||
|
||||
|
@ -232,7 +232,7 @@ declare interface ChartBasicStyle {
|
||||
/**
|
||||
* 对称柱状图方向
|
||||
*/
|
||||
layout: 'horizontal' | 'vertical'
|
||||
layout?: 'horizontal' | 'vertical'
|
||||
}
|
||||
/**
|
||||
* 表头属性
|
||||
@ -482,6 +482,10 @@ declare interface ChartMiscAttr {
|
||||
* 地图线条宽度
|
||||
*/
|
||||
mapLineWidth: number
|
||||
/**
|
||||
* 流向地图动画
|
||||
*/
|
||||
mapLineAnimate?: boolean
|
||||
/**
|
||||
* 流向地图动画间隔
|
||||
*/
|
||||
|
@ -221,6 +221,7 @@ watch(
|
||||
:themes="themes"
|
||||
:chart="chart"
|
||||
@onBasicStyleChange="onBasicStyleChange"
|
||||
@onMiscChange="onMiscChange"
|
||||
/>
|
||||
</el-collapse-item>
|
||||
<collapse-switch-item
|
||||
|
@ -1,6 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, PropType, reactive, watch } from 'vue'
|
||||
import { COLOR_PANEL, DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||
import {
|
||||
COLOR_PANEL,
|
||||
DEFAULT_BASIC_STYLE,
|
||||
DEFAULT_MISC
|
||||
} from '@/views/chart/components/editor/util/chart'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import CustomColorStyleSelect from '@/views/chart/components/editor/editor-style/components/CustomColorStyleSelect.vue'
|
||||
import { cloneDeep, defaultsDeep } from 'lodash-es'
|
||||
@ -28,6 +32,7 @@ const showProperty = prop => props.propertyInner?.includes(prop)
|
||||
const predefineColors = COLOR_PANEL
|
||||
const state = reactive({
|
||||
basicStyleForm: JSON.parse(JSON.stringify(DEFAULT_BASIC_STYLE)) as ChartBasicStyle,
|
||||
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr,
|
||||
customColor: null,
|
||||
colorIndex: 0,
|
||||
fieldColumnWidth: {
|
||||
@ -38,6 +43,7 @@ const state = reactive({
|
||||
watch(
|
||||
[
|
||||
() => props.chart.customAttr.basicStyle,
|
||||
() => props.chart.customAttr.misc,
|
||||
() => props.chart.customAttr.tableHeader,
|
||||
() => props.chart.xAxis,
|
||||
() => props.chart.yAxis
|
||||
@ -47,14 +53,19 @@ watch(
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
const emit = defineEmits(['onBasicStyleChange'])
|
||||
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
|
||||
const changeBasicStyle = (prop?: string, requestData = false) => {
|
||||
emit('onBasicStyleChange', { data: state.basicStyleForm, requestData }, prop)
|
||||
}
|
||||
const changeMisc = prop => {
|
||||
emit('onMiscChange', { data: state.miscForm, requestData: true }, prop)
|
||||
}
|
||||
const init = () => {
|
||||
const basicStyle = cloneDeep(props.chart.customAttr.basicStyle)
|
||||
const miscStyle = cloneDeep(props.chart.customAttr.misc)
|
||||
configCompat(basicStyle)
|
||||
state.basicStyleForm = defaultsDeep(basicStyle, cloneDeep(DEFAULT_BASIC_STYLE)) as ChartBasicStyle
|
||||
state.miscForm = defaultsDeep(miscStyle, cloneDeep(DEFAULT_MISC)) as ChartMiscAttr
|
||||
if (!state.customColor) {
|
||||
state.customColor = state.basicStyleForm.colors[0]
|
||||
state.colorIndex = 0
|
||||
@ -177,6 +188,12 @@ const mapStyleOptions = [
|
||||
{ name: t('chart.map_style_wine'), value: 'wine' }
|
||||
]
|
||||
|
||||
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' }
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
})
|
||||
@ -268,7 +285,236 @@ onMounted(() => {
|
||||
<el-radio :effect="themes" label="vertical">{{ t('chart.vertical') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<!--flow map begin-->
|
||||
<div class="map-setting" v-if="showProperty('mapStyle')">
|
||||
<div class="map-style">
|
||||
<el-row style="flex: 1">
|
||||
<el-col>
|
||||
<el-form-item
|
||||
:label="t('chart.chart_map') + t('chart.map_style')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
>
|
||||
<el-select
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.mapStyle"
|
||||
@change="changeBasicStyle('mapStyle')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in mapStyleOptions"
|
||||
: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.chart_map') + t('chart.map_pitch') }}
|
||||
</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="90"
|
||||
v-model="state.miscForm.mapPitch"
|
||||
@change="changeMisc('mapPitch')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-flow-style">
|
||||
<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="changeMisc('mapLineSourceColor')"
|
||||
/>
|
||||
</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="changeMisc('mapLineTargetColor')"
|
||||
/>
|
||||
</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="changeMisc('mapLineSourceColor')"
|
||||
/>
|
||||
</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="changeBasicStyle('alpha')"
|
||||
>
|
||||
<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>
|
||||
<!--flow map end-->
|
||||
<!--map start-->
|
||||
<el-row :gutter="8">
|
||||
<el-col :span="12" v-if="showProperty('areaBorderColor')">
|
||||
@ -658,27 +904,6 @@ onMounted(() => {
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!--radar end-->
|
||||
<!--flow map begin-->
|
||||
<el-form-item
|
||||
:label="t('chart.map_style')"
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('mapStyle')"
|
||||
>
|
||||
<el-select
|
||||
:effect="themes"
|
||||
v-model="state.basicStyleForm.mapStyle"
|
||||
@change="changeBasicStyle('mapStyle')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in mapStyleOptions"
|
||||
:key="item.name"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!--flow map end-->
|
||||
<!--scatter start-->
|
||||
<el-form-item
|
||||
:label="t('chart.bubble_symbol')"
|
||||
|
@ -1223,14 +1223,14 @@ export const CHART_TYPE_CONFIGS = [
|
||||
category: 'compare',
|
||||
value: 'bidirectional-bar',
|
||||
title: t('chart.chart_bidirectional_bar'),
|
||||
icon: 'percentage-bar-stack-horizontal'
|
||||
icon: 'bar-bidirectional'
|
||||
},
|
||||
{
|
||||
render: 'antv',
|
||||
category: 'compare',
|
||||
value: 'progress-bar',
|
||||
title: t('chart.chart_progress_bar'),
|
||||
icon: 'percentage-bar-stack-horizontal'
|
||||
icon: 'bar-progress'
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -1308,6 +1308,13 @@ export const CHART_TYPE_CONFIGS = [
|
||||
value: 'bubble-map',
|
||||
title: t('chart.chart_bubble_map'),
|
||||
icon: 'bubble-map'
|
||||
},
|
||||
{
|
||||
render: 'antv',
|
||||
category: 'map',
|
||||
value: 'flow-map',
|
||||
title: t('chart.chart_flow_map'),
|
||||
icon: 'flow-map'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -0,0 +1,138 @@
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import {
|
||||
L7ChartView,
|
||||
L7Config,
|
||||
L7DrawConfig,
|
||||
L7Wrapper
|
||||
} from '@/views/chart/components/js/panel/types/impl/l7'
|
||||
import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common'
|
||||
import { flow, parseJson } from '@/views/chart/components/js/util'
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
import { GaodeMap } from '@antv/l7-maps'
|
||||
import { Scene } from '@antv/l7-scene'
|
||||
import { LineLayer } from '@antv/l7-layers'
|
||||
import { queryMapKeyApi } from '@/api/setting/sysParameter'
|
||||
const { t } = useI18n()
|
||||
|
||||
/**
|
||||
* 流向地图
|
||||
*/
|
||||
export class FlowMap extends L7ChartView<Scene, L7Config> {
|
||||
properties: EditorProperty[] = [
|
||||
'background-overall-component',
|
||||
'basic-style-selector',
|
||||
'title-selector'
|
||||
]
|
||||
propertyInner: EditorPropertyInner = {
|
||||
...MAP_EDITOR_PROPERTY_INNER,
|
||||
'basic-style-selector': ['mapStyle', 'zoom']
|
||||
}
|
||||
axis: AxisType[] = ['xAxis', 'xAxisExt', 'filter']
|
||||
axisConfig: AxisConfig = {
|
||||
xAxis: {
|
||||
name: `起点经纬度 / ${t('chart.dimension')}`,
|
||||
type: 'd',
|
||||
limit: 2
|
||||
},
|
||||
xAxisExt: {
|
||||
name: `终点经纬度 / ${t('chart.dimension')}`,
|
||||
type: 'd',
|
||||
limit: 2
|
||||
}
|
||||
}
|
||||
constructor() {
|
||||
super('flow-map', [])
|
||||
}
|
||||
|
||||
async drawChart(drawOption: L7DrawConfig<L7Config>) {
|
||||
const { chart, container } = drawOption
|
||||
const xAxis = deepCopy(chart.xAxis)
|
||||
const xAxisExt = deepCopy(chart.xAxisExt)
|
||||
let basicStyle
|
||||
let miscStyle
|
||||
if (chart.customAttr) {
|
||||
basicStyle = parseJson(chart.customAttr).basicStyle
|
||||
miscStyle = parseJson(chart.customAttr).misc
|
||||
}
|
||||
const flowLineStyle = {
|
||||
type: miscStyle.mapLineType,
|
||||
size: miscStyle.mapLineWidth,
|
||||
animate: miscStyle.mapLineAnimate,
|
||||
animateDuration: miscStyle.mapLineAnimateDuration,
|
||||
gradient: miscStyle.mapLineGradient,
|
||||
sourceColor: miscStyle.mapLineSourceColor,
|
||||
targetColor: miscStyle.mapLineTargetColor,
|
||||
alpha: basicStyle.alpha
|
||||
}
|
||||
const mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}`
|
||||
const key = await this.getMapKey()
|
||||
// 底层
|
||||
const scene = new Scene({
|
||||
id: container,
|
||||
logoVisible: false,
|
||||
map: new GaodeMap({
|
||||
token: key ?? undefined,
|
||||
style: mapStyle,
|
||||
pitch: miscStyle.mapPitch,
|
||||
zoom: 2.5
|
||||
})
|
||||
})
|
||||
if (xAxis?.length < 2 || xAxisExt?.length < 2) {
|
||||
return new L7Wrapper(scene, undefined)
|
||||
}
|
||||
const config: L7Config = new LineLayer({
|
||||
name: 'line',
|
||||
blend: 'normal',
|
||||
autoFit: true
|
||||
})
|
||||
.source(chart.data?.tableRow ? chart.data.tableRow : [], {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: xAxis[0].dataeaseName,
|
||||
y: xAxis[1].dataeaseName,
|
||||
x1: xAxisExt[0].dataeaseName,
|
||||
y1: xAxisExt[1].dataeaseName
|
||||
}
|
||||
})
|
||||
.size(flowLineStyle.size)
|
||||
.shape(flowLineStyle.type)
|
||||
.animate({
|
||||
enable: flowLineStyle.animate,
|
||||
duration: flowLineStyle.animateDuration,
|
||||
interval: 1,
|
||||
trailLength: 1
|
||||
})
|
||||
if (flowLineStyle.gradient) {
|
||||
config.style({
|
||||
sourceColor: flowLineStyle.sourceColor,
|
||||
targetColor: flowLineStyle.targetColor,
|
||||
opacity: flowLineStyle.alpha / 100
|
||||
})
|
||||
} else {
|
||||
config
|
||||
.style({
|
||||
opacity: flowLineStyle.alpha / 100
|
||||
})
|
||||
.color(flowLineStyle.sourceColor)
|
||||
}
|
||||
this.configZoomButton(chart, scene)
|
||||
return new L7Wrapper(scene, config)
|
||||
}
|
||||
|
||||
getMapKey = async () => {
|
||||
const key = 'online-map-key'
|
||||
if (!localStorage.getItem(key)) {
|
||||
await queryMapKeyApi().then(res => localStorage.setItem(key, res.data))
|
||||
}
|
||||
return localStorage.getItem(key)
|
||||
}
|
||||
|
||||
setupDefaultOptions(chart: ChartObj): ChartObj {
|
||||
chart.customAttr.misc.mapLineAnimate = true
|
||||
return chart
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, config: L7Config): L7Config {
|
||||
return flow(this.configEmptyDataStrategy)(chart, config)
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import type { Plot as L7Plot, PlotOptions } from '@antv/l7plot/dist/esm'
|
||||
import { Zoom } from '@antv/l7'
|
||||
import { createL7Icon } from '@antv/l7-component/es/utils/icon'
|
||||
import { DOM } from '@antv/l7-utils'
|
||||
import { Scene } from '@antv/l7-scene'
|
||||
|
||||
export function getPadding(chart: Chart): number[] {
|
||||
if (chart.drill) {
|
||||
@ -1023,7 +1024,7 @@ class CustomZoom extends Zoom {
|
||||
this['updateDisabled']()
|
||||
}
|
||||
}
|
||||
export function configL7Zoom(chart: Chart, plot: L7Plot<PlotOptions>) {
|
||||
export function configL7Zoom(chart: Chart, plot: L7Plot<PlotOptions> | Scene) {
|
||||
const { basicStyle } = parseJson(chart.customAttr)
|
||||
if (
|
||||
(basicStyle.suspension === false && basicStyle.showZoom === undefined) ||
|
||||
@ -1031,14 +1032,15 @@ export function configL7Zoom(chart: Chart, plot: L7Plot<PlotOptions>) {
|
||||
) {
|
||||
return
|
||||
}
|
||||
plot.once('loaded', () => {
|
||||
const plotScene = plot instanceof Scene ? plot : plot.scene
|
||||
plotScene.once('loaded', () => {
|
||||
const zoomOptions = {
|
||||
initZoom: plot.scene.getZoom(),
|
||||
center: plot.scene.getCenter(),
|
||||
initZoom: plotScene.getZoom(),
|
||||
center: plotScene.getCenter(),
|
||||
buttonColor: basicStyle.zoomButtonColor,
|
||||
buttonBackground: basicStyle.zoomBackground
|
||||
} as any
|
||||
plot.scene.addControl(new CustomZoom(zoomOptions))
|
||||
plotScene.addControl(new CustomZoom(zoomOptions))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,95 @@
|
||||
import { Scene } from '@antv/l7-scene'
|
||||
import {
|
||||
AntVAbstractChartView,
|
||||
AntVDrawOptions,
|
||||
ChartLibraryType,
|
||||
ChartWrapper
|
||||
} from '@/views/chart/components/js/panel/types'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { parseJson } from '@/views/chart/components/js/util'
|
||||
import { ILayer } from '@antv/l7plot'
|
||||
import { configL7Zoom } from '@/views/chart/components/js/panel/common/common_antv'
|
||||
|
||||
export type L7DrawConfig<P> = AntVDrawOptions<P>
|
||||
export interface L7Config extends ILayer {
|
||||
handleConfig?: (arg0: Scene) => void
|
||||
[key: string]: string | any
|
||||
}
|
||||
export class L7Wrapper<
|
||||
O extends L7Config | Array<L7Config>,
|
||||
S extends Scene
|
||||
> extends ChartWrapper<S> {
|
||||
private readonly config: O | Array<O>
|
||||
private readonly scene: S | null = null
|
||||
constructor(scene: S, l7config: O | Array<O> | undefined) {
|
||||
super()
|
||||
this.chartInstance = scene
|
||||
this.config = l7config
|
||||
this.scene = scene
|
||||
}
|
||||
destroy = () => {
|
||||
if (!this.chartInstance) {
|
||||
return
|
||||
}
|
||||
this.chartInstance?.destroy()
|
||||
}
|
||||
render = () => {
|
||||
if (this.scene && this.config) {
|
||||
this.scene.on('loaded', () => {
|
||||
if (Array.isArray(this.config)) {
|
||||
this.config?.forEach(p => {
|
||||
this.handleConfig(p)
|
||||
})
|
||||
} else {
|
||||
this.handleConfig(this.config)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleConfig = (config: L7Config) => {
|
||||
if (config.handleConfig) {
|
||||
config.handleConfig?.(this.scene)
|
||||
} else {
|
||||
this.scene.addLayer(config)
|
||||
}
|
||||
}
|
||||
}
|
||||
export abstract class L7ChartView<
|
||||
S extends Scene,
|
||||
O extends L7Config
|
||||
> extends AntVAbstractChartView {
|
||||
public abstract drawChart(drawOption: L7DrawConfig<O>): L7Wrapper<O, S> | any
|
||||
|
||||
protected configEmptyDataStrategy(chart: Chart, options: O): O {
|
||||
const { functionCfg } = parseJson(chart.senior)
|
||||
const emptyDataStrategy = functionCfg.emptyDataStrategy
|
||||
if (!emptyDataStrategy || emptyDataStrategy === 'breakLine') {
|
||||
return options
|
||||
}
|
||||
const data = cloneDeep(options.sourceOption.data)
|
||||
if (emptyDataStrategy === 'setZero') {
|
||||
data.forEach(item => {
|
||||
item.value === null && (item.value = 0)
|
||||
})
|
||||
}
|
||||
if (emptyDataStrategy === 'ignoreData') {
|
||||
for (let i = data.length - 1; i >= 0; i--) {
|
||||
if (data[i].value === null) {
|
||||
data.splice(i, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
options.sourceOption.data = data
|
||||
return options
|
||||
}
|
||||
|
||||
protected configZoomButton(chart: Chart, plot: S) {
|
||||
configL7Zoom(chart, plot)
|
||||
}
|
||||
|
||||
protected constructor(name: string, defaultData: any[]) {
|
||||
super(ChartLibraryType.L7, name, defaultData)
|
||||
}
|
||||
protected abstract setupOptions(chart: Chart, options: O): O
|
||||
}
|
@ -11,6 +11,7 @@ export enum ChartRenderType {
|
||||
export enum ChartLibraryType {
|
||||
G2_PLOT = 'g2plot',
|
||||
L7_PLOT = 'l7plot',
|
||||
L7 = 'l7',
|
||||
ECHARTS = 'echarts',
|
||||
S2 = 's2',
|
||||
RICH_TEXT = 'rich-text',
|
||||
|
@ -17,6 +17,7 @@ import { customAttrTrans, customStyleTrans, recursionTransObj } from '@/utils/ca
|
||||
import { deepCopy } from '@/utils/utils'
|
||||
import { trackBarStyleCheck } from '@/utils/canvasUtils'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { L7ChartView } from '@/views/chart/components/js/panel/types/impl/l7'
|
||||
|
||||
const dvMainStore = dvMainStoreWithOut()
|
||||
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, embeddedCallBack } =
|
||||
@ -116,7 +117,7 @@ const calcData = async (view, callback) => {
|
||||
callback?.()
|
||||
})
|
||||
} else {
|
||||
if (['bubble-map', 'map'].includes(view.type)) {
|
||||
if (['bubble-map', 'map', 'flow-map'].includes(view.type)) {
|
||||
await renderChart(view, callback)
|
||||
}
|
||||
callback?.()
|
||||
@ -141,6 +142,9 @@ const renderChart = async (view, callback?) => {
|
||||
case ChartLibraryType.L7_PLOT:
|
||||
await renderL7Plot(chart, chartView as L7PlotChartView<any, any>, callback)
|
||||
break
|
||||
case ChartLibraryType.L7:
|
||||
await renderL7(chart, chartView as L7ChartView<any, any>, callback)
|
||||
break
|
||||
case ChartLibraryType.G2_PLOT:
|
||||
renderG2Plot(chart, chartView as G2PlotChartView<any, any>)
|
||||
callback?.()
|
||||
@ -199,6 +203,23 @@ const renderL7Plot = async (chart: ChartObj, chartView: L7PlotChartView<any, any
|
||||
}, 500)
|
||||
}
|
||||
|
||||
let mapL7Timer: number
|
||||
const renderL7 = async (chart: ChartObj, chartView: L7ChartView<any, any>, callback) => {
|
||||
mapL7Timer && clearTimeout(mapL7Timer)
|
||||
mapL7Timer = setTimeout(async () => {
|
||||
myChart?.destroy()
|
||||
myChart = await chartView.drawChart({
|
||||
chartObj: myChart,
|
||||
container: containerId,
|
||||
chart: chart,
|
||||
action
|
||||
})
|
||||
myChart?.render()
|
||||
callback?.()
|
||||
emit('resetLoading')
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const pointClickTrans = () => {
|
||||
if (embeddedCallBack.value === 'yes') {
|
||||
trackClick('pointClick')
|
||||
@ -333,7 +354,7 @@ defineExpose({
|
||||
})
|
||||
let resizeObserver
|
||||
const TOLERANCE = 0.01
|
||||
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map']
|
||||
const RESIZE_MONITOR_CHARTS = ['map', 'bubble-map', 'flow-map']
|
||||
onMounted(() => {
|
||||
const containerDom = document.getElementById(containerId)
|
||||
const { offsetWidth, offsetHeight } = containerDom
|
||||
|
@ -40,7 +40,6 @@ import { Base64 } from 'js-base64'
|
||||
import DeRichTextView from '@/custom-component/rich-text/DeRichTextView.vue'
|
||||
import ChartEmptyInfo from '@/views/chart/components/views/components/ChartEmptyInfo.vue'
|
||||
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
|
||||
import { useAppStoreWithOut } from '@/store/modules/app'
|
||||
|
||||
const { wsCache } = useCache()
|
||||
const chartComponent = ref<any>()
|
||||
@ -105,7 +104,6 @@ const props = defineProps({
|
||||
})
|
||||
const dynamicAreaId = ref('')
|
||||
const { view, showPosition, element, active, searchCount, scale } = toRefs(props)
|
||||
const appStore = useAppStoreWithOut()
|
||||
|
||||
const titleShow = computed(
|
||||
() =>
|
||||
@ -242,7 +240,6 @@ watch([() => curComponent.value], () => {
|
||||
})
|
||||
}
|
||||
})
|
||||
const isDataEaseBi = computed(() => appStore.getIsDataEaseBi)
|
||||
|
||||
const chartExtRequest = shallowRef(null)
|
||||
provide('chartExtRequest', chartExtRequest)
|
||||
@ -568,7 +565,7 @@ const chartAreaShow = computed(() => {
|
||||
return true
|
||||
}
|
||||
if (view.value.customAttr.map.id) {
|
||||
const MAP_CHARTS = ['map', 'bubble-map']
|
||||
const MAP_CHARTS = ['map', 'bubble-map', 'flow-map']
|
||||
if (MAP_CHARTS.includes(view.value.type)) {
|
||||
return true
|
||||
}
|
||||
@ -726,7 +723,9 @@ const titleIconStyle = computed(() => {
|
||||
:view="view"
|
||||
:show-position="showPosition"
|
||||
:element="element"
|
||||
v-else-if="showChartView(ChartLibraryType.G2_PLOT, ChartLibraryType.L7_PLOT)"
|
||||
v-else-if="
|
||||
showChartView(ChartLibraryType.G2_PLOT, ChartLibraryType.L7_PLOT, ChartLibraryType.L7)
|
||||
"
|
||||
ref="chartComponent"
|
||||
@onChartClick="chartClick"
|
||||
@onPointClick="onPointClick"
|
||||
|
Loading…
Reference in New Issue
Block a user