feat(图表): 支持圆形填充图

This commit is contained in:
jianneng-fit2cloud 2024-12-16 19:44:58 +08:00 committed by jianneng-fit2cloud
parent 7aff0c0dbe
commit 7f5e2174f4
20 changed files with 494 additions and 14 deletions

View File

@ -0,0 +1,16 @@
<svg width="80" height="56" viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
<circle cx="40" cy="28" r="25"/>
<circle cx="40" cy="14" r="8" fill="#26DCC3"/>
<circle cx="43" cy="42" r="5" fill="#00D6B9"/>
<circle cx="31" cy="43" r="5" fill="#3370FF"/>
<circle cx="28" cy="19" r="3" fill="#00D6B9"/>
<circle cx="53" cy="29" r="10" fill="#3370FF"/>
<circle cx="34" cy="29" r="7" fill="#3370FF"/>
<circle cx="38.5" cy="11.5" r="3.5" fill="#99EFE3"/>
<circle cx="43.5" cy="16.5" r="2.5" fill="#99EFE3"/>
<circle cx="49.5" cy="27.5" r="4.5" fill="#ADC6FF"/>
<circle cx="58" cy="27" r="3" fill="#ADC6FF"/>
<circle cx="58" cy="27" r="3" fill="#ADC6FF"/>
<circle cx="55" cy="34" r="3" fill="#ADC6FF"/>
</svg>

After

Width:  |  Height:  |  Size: 735 B

View File

@ -0,0 +1,15 @@
<svg width="80" height="56" viewBox="0 0 80 56" xmlns="http://www.w3.org/2000/svg">
<circle cx="40" cy="28" r="25"/>
<circle cx="40" cy="14" r="8" fill="#26DCC3"/>
<circle cx="43" cy="42" r="5" fill="#00D6B9"/>
<circle cx="31" cy="43" r="5" fill="#3370FF"/>
<circle cx="28" cy="19" r="3" fill="#00D6B9"/>
<circle cx="53" cy="29" r="10" fill="#3370FF"/>
<circle cx="34" cy="29" r="7" fill="#3370FF"/>
<circle cx="38.5" cy="11.5" r="3.5" fill="#99EFE3"/>
<circle cx="43.5" cy="16.5" r="2.5" fill="#99EFE3"/>
<circle cx="49.5" cy="27.5" r="4.5" fill="#ADC6FF"/>
<circle cx="58" cy="27" r="3" fill="#ADC6FF"/>
<circle cx="58" cy="27" r="3" fill="#ADC6FF"/>
<circle cx="55" cy="34" r="3" fill="#ADC6FF"/>
</svg>

After

Width:  |  Height:  |  Size: 734 B

View File

@ -0,0 +1,15 @@
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="40" cy="28" r="25" fill="#D6E2FF"/>
<circle cx="40" cy="14" r="8" fill="#26DCC3"/>
<circle cx="43" cy="42" r="5" fill="#00D6B9"/>
<circle cx="31" cy="43" r="5" fill="#3370FF"/>
<circle cx="28" cy="19" r="3" fill="#00D6B9"/>
<circle cx="53" cy="29" r="10" fill="#3370FF"/>
<circle cx="34" cy="29" r="7" fill="#3370FF"/>
<circle cx="38.5" cy="11.5" r="3.5" fill="#99EFE3"/>
<circle cx="43.5" cy="16.5" r="2.5" fill="#99EFE3"/>
<circle cx="49.5" cy="27.5" r="4.5" fill="#ADC6FF"/>
<circle cx="58" cy="27" r="3" fill="#ADC6FF"/>
<circle cx="58" cy="27" r="3" fill="#ADC6FF"/>
<circle cx="55" cy="34" r="3" fill="#ADC6FF"/>
</svg>

After

Width:  |  Height:  |  Size: 760 B

View File

@ -73,6 +73,7 @@ import { lockStoreWithOut } from '@/store/modules/data-visualization/lock'
import ContextMenuAsideDetails from '@/components/data-visualization/canvas/ContextMenuAsideDetails.vue'
import ComposeShow from '@/components/data-visualization/canvas/ComposeShow.vue'
import { composeStoreWithOut } from '@/store/modules/data-visualization/compose'
import circlePackingOrigin from '@/assets/svg/circle-packing-origin.svg'
const dropdownMore = ref(null)
const lockStore = lockStoreWithOut()
@ -233,7 +234,8 @@ const iconMap = {
'waterfall-origin': waterfallOrigin,
'word-cloud-origin': wordCloudOrigin,
't-heatmap-origin': tHeatmapOrigin,
group: group
group: group,
'circle-packing-origin': circlePackingOrigin
}
const getIconName = item => {
if (item.component === 'UserView') {

View File

@ -80,6 +80,7 @@ import RealTimeGroup from '@/components/data-visualization/RealTimeGroup.vue'
import { contextmenuStoreWithOut } from '@/store/modules/data-visualization/contextmenu'
import RealTimeTab from '@/components/data-visualization/RealTimeTab.vue'
import { useI18n } from '@/hooks/web/useI18n'
import circlePackingOrigin from '@/assets/svg/circle-packing-origin.svg'
const dropdownMore = ref(null)
const lockStore = lockStoreWithOut()
@ -329,7 +330,8 @@ const iconMap = {
'word-cloud-origin': wordCloudOrigin,
't-heatmap-origin': tHeatmapOrigin,
'picture-group-origin': pictureGroupOrigin,
group: group
group: group,
'circle-packing-origin': circlePackingOrigin
}
const getIconName = item => {
if (item.component === 'UserView') {

View File

@ -344,7 +344,8 @@ const boardMoveActive = computed(() => {
'table-pivot',
'symbolic-map',
'heat-map',
't-heatmap'
't-heatmap',
'circle-packing'
]
return element.value.isPlugin || CHARTS.includes(element.value.innerType)
})

View File

@ -42,6 +42,7 @@ import treemapDark from '@/assets/svg/treemap-dark.svg'
import waterfallDark from '@/assets/svg/waterfall-dark.svg'
import wordCloudDark from '@/assets/svg/word-cloud-dark.svg'
import tHeatmapDark from '@/assets/svg/t-heatmap-dark.svg'
import circlePackingDark from '@/assets/svg/circle-packing-dark.svg'
const iconChartDarkMap = {
'area-dark': areaDark,
@ -87,7 +88,8 @@ const iconChartDarkMap = {
'treemap-dark': treemapDark,
'waterfall-dark': waterfallDark,
'word-cloud-dark': wordCloudDark,
't-heatmap-dark': tHeatmapDark
't-heatmap-dark': tHeatmapDark,
'circle-packing-dark': circlePackingDark
}
export { iconChartDarkMap }

View File

@ -45,6 +45,7 @@ import tHeatmap from '@/assets/svg/t-heatmap.svg'
import pictureGroup from '@/assets/svg/picture-group.svg'
import filter from '@/assets/svg/filter.svg'
import outerParams from '@/assets/svg/icon_params_setting.svg'
import circlePacking from '@/assets/svg/circle-packing.svg'
const iconChartMap = {
'area-stack': areaStack,
@ -93,7 +94,8 @@ const iconChartMap = {
't-heatmap': tHeatmap,
'picture-group': pictureGroup,
filter: filter,
outerParams: outerParams
outerParams: outerParams,
'circle-packing': circlePacking
}
export { iconChartMap }

View File

@ -1919,7 +1919,13 @@ export default {
'When Customizing, Supports SVG, JPG, JPEG, and PNG files up to 1MB',
size_range: 'Size Range',
x_axis_constant_line: 'X-axis Constant Line',
y_axis_constant_line: 'Y-axis Constant Line'
y_axis_constant_line: 'Y-axis Constant Line',
chart_circle_packing: 'Circle Packing Chart',
circle_packing_name: 'Circle Name',
circle_packing_value: 'Circle Size',
circle_packing_border_color: 'Border color',
circle_packing_border_width: 'Border width',
circle_packing_padding: 'Circle padding'
},
dataset: {
scope_edit: 'Only effective when editing',

View File

@ -1919,7 +1919,13 @@ Scatter chart (bubble) chart: {a} (series name), {b} (data name), {c} (value arr
x_axis_constant_line: 'X-axis Constant Line',
y_axis_constant_line: 'Y-axis Constant Line',
sort_priority: 'Sort Priority Setting',
sort_priority_tip: 'Top-down, sorting priority from highest to lowest'
sort_priority_tip: 'Top-down, sorting priority from highest to lowest',
chart_circle_packing: 'Circle packing chart',
circle_packing_name: 'Circle name',
circle_packing_value: 'Circle size',
circle_packing_border_color: 'Border color',
circle_packing_border_width: 'Border width',
circle_packing_padding: 'Circle padding'
},
dataset: {
scope_edit: 'Only effective when editing',

View File

@ -1877,7 +1877,13 @@ export default {
x_axis_constant_line: 'X 軸恆線',
y_axis_constant_line: 'Y 軸恆線',
sort_priority: '排序優先級設置',
sort_priority_tip: '自上而下排序優先級從高到低'
sort_priority_tip: '自上而下排序優先級從高到低',
chart_circle_packing: '圓形填充圖',
circle_packing_name: '圓形名稱',
circle_packing_value: '圓形大小',
circle_packing_border_color: '邊線顏色',
circle_packing_border_width: '邊線寬度',
circle_packing_padding: 'Circle padding'
},
dataset: {
scope_edit: '僅編輯時生效',

View File

@ -1879,7 +1879,13 @@ export default {
x_axis_constant_line: 'X 轴恒线',
y_axis_constant_line: 'Y 轴恒线',
sort_priority: '排序优先级设置',
sort_priority_tip: '自上而下排序优先级从高到低'
sort_priority_tip: '自上而下排序优先级从高到低',
chart_circle_packing: '圆形填充图',
circle_packing_name: '圆形名称',
circle_packing_value: '圆形大小',
circle_packing_border_color: '边线颜色',
circle_packing_border_width: '边线宽度',
circle_packing_padding: '圓形間距'
},
dataset: {
scope_edit: '仅编辑时生效',

View File

@ -350,6 +350,18 @@ declare interface ChartBasicStyle {
* 雷达图面积颜色开关
*/
radarAreaColor: boolean
/**
* 圆形填充图边线颜色
*/
circleBorderColor: string
/**
* 圆形填充图边线宽度
*/
circleBorderWidth: number
/**
* 圆形填充图间距
*/
circlePadding: number
}
/**
* 表头属性

View File

@ -93,6 +93,9 @@ const initFieldCtrl = () => {
})
}
}
const isCirclePacking = computed(() => {
return equalsAny(props.chart.type, 'circle-packing')
})
onMounted(() => {
init()
})
@ -196,7 +199,9 @@ onMounted(() => {
</el-radio>
<el-radio v-if="isRichText" :effect="themes" :label="'custom'"> 自定义 </el-radio>
<template v-if="!isRichText">
<el-radio :effect="themes" :label="'setZero'">{{ t('chart.set_zero') }}</el-radio>
<el-radio v-if="!isCirclePacking" :effect="themes" :label="'setZero'">{{
t('chart.set_zero')
}}</el-radio>
<el-radio v-if="showIgnoreOption" :effect="themes" :label="'ignoreData'">
{{ t('chart.ignore_data') }}
</el-radio>

View File

@ -13,7 +13,7 @@ import { SERIES_NUMBER_FIELD } from '@antv/s2'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { storeToRefs } from 'pinia'
import { isNumber } from 'mathjs'
import { ElMessage, UploadProps } from 'element-plus-secondary'
import { ElFormItem, ElInputNumber, ElMessage, UploadProps } from 'element-plus-secondary'
import { svgStrToUrl } from '../../../js/util'
const dvMainStore = dvMainStoreWithOut()
@ -1389,6 +1389,69 @@ onMounted(() => {
</el-row>
</div>
<!-- pie/rose end -->
<!-- circle-packing start -->
<div v-if="showProperty('circleBorderStyle')">
<div class="alpha-setting">
<el-row style="display: flex; width: 100%">
<el-col :span="10">
<el-form-item
:label="t('chart.circle_packing_border_color')"
class="form-item"
:class="'form-item-' + themes"
>
<el-color-picker
v-model="state.basicStyleForm.circleBorderColor"
class="color-picker-style"
:triggerWidth="65"
is-custom
show-alpha
:predefine="state.predefineColors"
@change="changeBasicStyle('circleBorderColor')"
>
</el-color-picker>
</el-form-item>
</el-col>
<el-col :span="14">
<el-form-item
:label="t('chart.circle_packing_border_width')"
class="form-item"
:class="'form-item-' + themes"
>
<el-input-number
:min="0"
:max="50"
:effect="themes"
controls-position="right"
v-model="state.basicStyleForm.circleBorderWidth"
class="color-picker-style"
@change="changeBasicStyle('circleBorderWidth')"
>
</el-input-number>
</el-form-item>
</el-col>
</el-row>
</div>
<el-row>
<el-form-item
style="width: 150px"
:label="t('chart.circle_packing_padding')"
class="form-item"
:class="'form-item-' + themes"
>
<el-input-number
:min="0"
:max="10"
:effect="themes"
controls-position="right"
v-model="state.basicStyleForm.circlePadding"
class="color-picker-style"
@change="changeBasicStyle('circlePadding')"
>
</el-input-number>
</el-form-item>
</el-row>
</div>
<!-- circle-packing end -->
</div>
</template>
<style scoped lang="less">

View File

@ -1520,6 +1520,13 @@ export const CHART_TYPE_CONFIGS = [
value: 'sankey',
title: t('chart.chart_sankey'),
icon: 'sankey'
},
{
render: 'antv',
category: 'distribute',
value: 'circle-packing',
title: t('chart.chart_circle_packing'),
icon: 'circle-packing'
}
]
},

View File

@ -0,0 +1,298 @@
import {
G2PlotChartView,
G2PlotDrawOptions
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import type {
CirclePacking as G2CirclePacking,
CirclePackingOptions
} from '@antv/g2plot/esm/plots/circle-packing'
import { flow, parseJson } from '@/views/chart/components/js/util'
import { getPadding } from '@/views/chart/components/js/panel/common/common_antv'
import { useI18n } from '@/hooks/web/useI18n'
import type { Datum } from '@antv/g2plot/esm/types/common'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { cloneDeep } from 'lodash-es'
const { t } = useI18n()
const DEFAULT_DATA = []
/**
* 圆形填充图
*/
export class CirclePacking extends G2PlotChartView<CirclePackingOptions, G2CirclePacking> {
properties: EditorProperty[] = [
'basic-style-selector',
'background-overall-component',
'border-style',
'label-selector',
'legend-selector',
'title-selector',
'tooltip-selector',
'jump-set',
'linkage'
]
propertyInner: EditorPropertyInner = {
'background-overall-component': ['all'],
'border-style': ['all'],
'basic-style-selector': ['colors', 'alpha', 'circleBorderStyle'],
'title-selector': [
'title',
'fontSize',
'color',
'hPosition',
'isItalic',
'isBolder',
'remarkShow',
'fontFamily',
'letterSpace',
'fontShadow'
],
'function-cfg': ['emptyDataStrategy'],
'label-selector': ['color', 'fontSize'],
'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'],
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'tooltipFormatter', 'show']
}
axis: AxisType[] = ['xAxis', 'yAxis', 'filter', 'drill']
axisConfig: AxisConfig = {
xAxis: {
name: `${t('chart.circle_packing_name')} / ${t('chart.dimension')}`,
type: 'd'
},
yAxis: {
name: `${t('chart.circle_packing_value')} / ${t('chart.quota')}`,
type: 'q',
limit: 1,
allowEmpty: true
}
}
async drawChart(drawOptions: G2PlotDrawOptions<G2CirclePacking>): Promise<G2CirclePacking> {
const { chart, container, action } = drawOptions
if (chart?.data?.tableRow?.length) {
// data
const data = chart.data.tableRow
const { xAxis, yAxis } = chart
const ySort = yAxis[0]?.sort ?? 'none'
const sort = {
sort: (a, b) =>
ySort === 'asc' ? a.value - b.value : ySort === 'desc' ? b.value - a.value : 0
}
// 根据配置获取节点的key用于构建节点树拖入字段顺序即为节点的层级
const nodeKeys = xAxis.map(item => item.dataeaseName)
// 将数据转为圆形填充图数据格式
const getCirclePackingData = () => {
const result = [{ name: t('commons.all'), children: [] }]
const addNode = (nodes, item, level) => {
if (level >= nodeKeys.length) return
const key = nodeKeys[level]
const value = item[key]
let node = nodes.find(n => n.name === value)
if (!node) {
node = { name: value, field: xAxis.find(f => f.dataeaseName === key), children: [] }
nodes.push(node)
}
if (level === nodeKeys.length - 1) {
node.value = yAxis.length ? item[yAxis[0].dataeaseName] : 1
} else {
addNode(node.children, item, level + 1)
}
}
data.forEach(item => addNode(result[0].children, item, 0))
return result[0]
}
// options
const initOptions: CirclePackingOptions = {
data: getCirclePackingData(),
appendPadding: getPadding(chart),
hierarchyConfig: {
...(ySort === 'none' ? {} : sort)
},
interactions: [
{
type: 'legend-active',
cfg: {
start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }],
end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }]
}
},
{
type: 'legend-filter',
cfg: {
start: [
{
trigger: 'legend-item:click',
action: [
'list-unchecked:toggle',
'data-filter:filter',
'element-active:reset',
'element-highlight:reset'
]
}
]
}
}
]
}
const options = this.setupOptions(chart, initOptions)
const { CirclePacking: G2CirclePacking } = await import(
'@antv/g2plot/esm/plots/circle-packing'
)
const newChart = new G2CirclePacking(container, options)
newChart.on('point:click', param => {
const data = param?.data?.data
if (data?.name === t('commons.all')) {
return
}
action({
x: param.x,
y: param.y,
data: {
data: {
...data,
dimensionList: [
{
id: data?.field?.id,
value: data.name,
name: data.name
}
]
}
}
})
})
return newChart
}
}
protected configBasicStyle(chart: Chart, options: CirclePackingOptions): CirclePackingOptions {
// size
const customAttr: DeepPartial<ChartAttr> = parseJson(chart.customAttr)
const s = JSON.parse(JSON.stringify(customAttr.basicStyle))
// 圆形边框样式
const pointStyle = {
stroke: s.circleBorderColor,
lineWidth: s.circleBorderWidth ?? 0
}
const padding = s.circlePadding
return {
...options,
hierarchyConfig: {
...options.hierarchyConfig,
padding: padding / 100 ?? 0
},
pointStyle
}
}
protected configLabel(chart: Chart, options: CirclePackingOptions): CirclePackingOptions {
const tmpOptions = super.configLabel(chart, options)
if (!tmpOptions.label) {
return {
...tmpOptions,
label: false
}
}
const { label: labelAttr } = parseJson(chart.customAttr)
const label = {
...tmpOptions.label,
textAlign: 'center',
offsetY: 5,
layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout,
formatter: (d: Datum, _point) => {
return d.children.length === 0 ? d.name : ''
}
}
return {
...tmpOptions,
label
}
}
protected configTooltip(chart: Chart, options: CirclePackingOptions): CirclePackingOptions {
const temOptions = super.configTooltip(chart, options)
if (!temOptions.tooltip) {
return temOptions
}
const tooltipAttr = parseJson(chart.customAttr).tooltip
return {
...temOptions,
tooltip: {
...temOptions,
fields: ['name', 'value'],
formatter: d => {
let value = d.value
if (tooltipAttr.tooltipFormatter) {
value = valueFormatter(value, tooltipAttr.tooltipFormatter)
}
return { name: d.name, value }
}
}
}
}
configEmptyDataStrategy(chart: Chart, options: CirclePackingOptions): CirclePackingOptions {
const { functionCfg } = parseJson(chart.senior)
const emptyDataStrategy = functionCfg.emptyDataStrategy
const setChildren = children => {
if (emptyDataStrategy === 'ignoreData') {
for (let i = children.length - 1; i >= 0; i--) {
let isNotNullChildren = []
if (children[i].children?.length) {
isNotNullChildren = children[i].children.filter(item => item.value !== null)
}
if (children[i].children?.length && isNotNullChildren.length) {
setChildren(children[i].children)
}
if (children[i]?.hasOwnProperty('value') && children[i].value === null) {
children.splice(i, 1)
}
if (!children[i]?.hasOwnProperty('value') && isNotNullChildren.length === 0) {
children.splice(i, 1)
}
}
} else {
for (let i = children.length - 1; i >= 0; i--) {
let isNotNullChildren = []
if (children[i].children?.length) {
isNotNullChildren = children[i].children.filter(item => item.value !== null)
if (!isNotNullChildren.length) {
children[i].children = []
continue
}
}
setChildren(children[i].children)
}
}
}
const data = cloneDeep(options.data.children)
setChildren(data)
options.data.children = data
return options
}
setupDefaultOptions(chart: ChartObj): ChartObj {
const { customAttr, customStyle, senior } = chart
const { label, basicStyle } = customAttr
const { legend } = customStyle
senior.functionCfg.emptyDataStrategy = 'ignoreData'
customAttr.label = {
...label,
show: true
}
legend.show = false
basicStyle.circleBorderWidth = 0
basicStyle.circleBorderColor = '#fff'
basicStyle.circlePadding = 0
return chart
}
protected setupOptions(chart: Chart, options: CirclePackingOptions): CirclePackingOptions {
return flow(
this.configTheme,
this.configEmptyDataStrategy,
this.configBasicStyle,
this.configLabel,
this.configTooltip,
this.configLegend
)(chart, options)
}
constructor() {
super('circle-packing', DEFAULT_DATA)
}
}

View File

@ -185,7 +185,6 @@ export function getLabel(chart: Chart) {
layout.push({ type: 'hide-overlap' })
} else {
layout.push({ type: 'limit-in-plot' })
layout.push({ type: 'fixed-overlap' })
layout.push({ type: 'hide-overlap' })
}
}

View File

@ -27,7 +27,8 @@ import { deepCopy, isMobile } from '@/utils/utils'
import { isDashboard, trackBarStyleCheck } from '@/utils/canvasUtils'
import { useEmitt } from '@/hooks/web/useEmitt'
import { L7ChartView } from '@/views/chart/components/js/panel/types/impl/l7'
import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n()
const dvMainStore = dvMainStoreWithOut()
const { nowPanelTrackInfo, nowPanelJumpInfo, mobileInPc, embeddedCallBack, inMobile } =
storeToRefs(dvMainStore)
@ -86,6 +87,7 @@ const emit = defineEmits([
const g2TypeSeries1 = ['bidirectional-bar']
const g2TypeSeries0 = ['bar-range']
const g2TypeTree = ['circle-packing']
const { view, showPosition, scale, terminal, suffixId } = toRefs(props)
@ -165,6 +167,14 @@ const checkSelected = param => {
return state.linkageActiveParam.name === param.field
} else if (g2TypeSeries0.includes(view.value.type)) {
return state.linkageActiveParam.category === param.category
} else if (g2TypeTree.includes(view.value.type)) {
if (
param.path?.startsWith(state.linkageActiveParam.name) ||
state.linkageActiveParam.name === t('commons.all')
) {
return true
}
return state.linkageActiveParam.name === param.name
} else {
return (
(state.linkageActiveParam.name === param.name ||
@ -444,7 +454,7 @@ const trackClick = trackAction => {
}
}
let quotaList = state.pointParam.data.quotaList
if (curView.type === 'bar-range') {
if (['bar-range', 'circle-packing'].includes(curView.type)) {
quotaList = state.pointParam.data.dimensionList
} else {
quotaList[0]['value'] = state.pointParam.data.value

View File

@ -352,6 +352,13 @@ const chartClick = param => {
ElMessage.error(t('chart.drill_field_error'))
return
}
if (
view.value.type === 'circle-packing' &&
(param.data?.childNodeCount === 0 || param.data.name === t('commons.all'))
) {
ElMessage.error(t('chart.last_layer'))
return
}
if (state.drillClickDimensionList.length < props.view.drillFields.length - 1) {
state.drillClickDimensionList.push({
dimensionList: param.data.dimensionList,