From 3b3cef670ceb46ea159562e87cc742957d1e5b0e Mon Sep 17 00:00:00 2001 From: jianneng-fit2cloud Date: Tue, 15 Oct 2024 18:38:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=9B=BE=E8=A1=A8):=20=E5=9C=B0=E5=9B=BE?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E5=9B=BE=E4=BE=8B?= =?UTF-8?q?=E5=8C=BA=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/models/chart/chart-attr.d.ts | 9 + .../components/LegendSelector.vue | 225 +++++++++++++++--- .../chart/components/editor/util/chart.ts | 2 + .../components/js/panel/charts/map/map.ts | 64 ++++- .../src/views/chart/components/js/util.ts | 6 +- 5 files changed, 263 insertions(+), 43 deletions(-) diff --git a/core/core-frontend/src/models/chart/chart-attr.d.ts b/core/core-frontend/src/models/chart/chart-attr.d.ts index 649cc0429e..746a28ddd6 100644 --- a/core/core-frontend/src/models/chart/chart-attr.d.ts +++ b/core/core-frontend/src/models/chart/chart-attr.d.ts @@ -681,6 +681,15 @@ declare interface ChartMiscAttr { * 显示图例个数 */ mapLegendNumber: number + /** + * 自定义区间类型,等间距,自定义 + */ + mapLegendRangeType: 'quantize' | 'custom' + /** + * 自定义区间类型为自定义(custom)时生效 + * 自定义区间值 + */ + mapLegendCustomRange: number[] /** * 流向地图配置 */ diff --git a/core/core-frontend/src/views/chart/components/editor/editor-style/components/LegendSelector.vue b/core/core-frontend/src/views/chart/components/editor/editor-style/components/LegendSelector.vue index 89d41a8f00..0a84fa0383 100644 --- a/core/core-frontend/src/views/chart/components/editor/editor-style/components/LegendSelector.vue +++ b/core/core-frontend/src/views/chart/components/editor/editor-style/components/LegendSelector.vue @@ -15,6 +15,7 @@ import { import { ElCol, ElRow, ElSpace } from 'element-plus-secondary' import { cloneDeep } from 'lodash-es' import { useEmitt } from '@/hooks/web/useEmitt' +import { getDynamicColorScale } from '@/views/chart/components/js/util' const { t } = useI18n() @@ -99,18 +100,114 @@ const init = () => { if (!state.legendForm.miscForm.hasOwnProperty('mapAutoLegend')) { state.legendForm.miscForm.mapAutoLegend = true } + if (!state.legendForm.miscForm.hasOwnProperty('mapLegendRangeType')) { + state.legendForm.miscForm.mapLegendRangeType = 'quantize' + } + if (!state.legendForm.miscForm.hasOwnProperty('mapLegendCustomRange')) { + state.legendForm.miscForm.mapLegendCustomRange = [] + } + initMapCustomRange() } } } } +// 存储地图默认的最大最小值 +const mapLegendDefaultRange = { + max: 0, + min: 0 +} +// 缓存原始的区间数据 +let mapLegendCustomRangeCacheList = [] const showProperty = prop => props.propertyInner?.includes(prop) const mapDefaultRange = args => { if (args.from === 'map') { - state.legendForm.miscForm.mapLegendMax = args.data.max - state.legendForm.miscForm.mapLegendMin = args.data.min - state.legendForm.miscForm.mapLegendNumber = args.data.legendNumber + const rangeCustom = state.legendForm.miscForm.mapLegendRangeType === 'custom' + if (!rangeCustom) { + state.legendForm.miscForm.mapLegendMax = cloneDeep(args.data.max) + state.legendForm.miscForm.mapLegendMin = cloneDeep(args.data.min) + } + state.legendForm.miscForm.mapLegendNumber = cloneDeep(args.data.legendNumber) + mapLegendCustomRangeCacheList = [] + mapLegendDefaultRange.max = cloneDeep(args.data.max) + mapLegendDefaultRange.min = cloneDeep(args.data.min) + const customRange = getDynamicColorScale( + mapLegendDefaultRange.min, + mapLegendDefaultRange.max, + args.data.legendNumber + ) + customRange.forEach((item, index) => { + if (index === 0) { + mapLegendCustomRangeCacheList.push(...item.value) + } else { + mapLegendCustomRangeCacheList.push(item.value[1]) + } + }) } } +const initMapCustomRange = () => { + const legendCustom = state.legendForm.miscForm.mapAutoLegend + const rangeCustom = state.legendForm.miscForm.mapLegendRangeType === 'custom' + const rangeCustomValue = state.legendForm.miscForm.mapLegendCustomRange + // 是自定义,并且自定义类型是自定义区间以及rangeCustomValue长度为0时,根据默认最大最小值计算区间值 + if (legendCustom && rangeCustom && rangeCustomValue.length === 0) { + calcMapCustomRange() + } +} +/** + * 计算自定义区间 + */ +const calcMapCustomRange = () => { + const customRange = getDynamicColorScale( + mapLegendDefaultRange.min, + mapLegendDefaultRange.max, + state.legendForm.miscForm.mapLegendNumber + ) + state.legendForm.miscForm.mapLegendCustomRange = [] + customRange.forEach((item, index) => { + if (index === 0) { + state.legendForm.miscForm.mapLegendCustomRange.push(...item.value) + } else { + state.legendForm.miscForm.mapLegendCustomRange.push(item.value[1]) + } + }) +} +/** + * 改变自定义区间类型 + * @param prop + */ +const changeLegendCustomType = (prop?) => { + const type = state.legendForm.miscForm.mapLegendRangeType + if (type === 'custom') { + state.legendForm.miscForm.mapLegendCustomRange = cloneDeep( + mapLegendCustomRangeCacheList.slice(0, state.legendForm.miscForm.mapLegendNumber + 1) + ) + } else { + state.legendForm.miscForm.mapLegendCustomRange = [] + } + prop ? changeMisc(prop) : '' +} +/** + * 改变自定义区间个数 + * @param prop + */ +const changeLegendNumber = (prop?) => { + if (!state.legendForm.miscForm.mapLegendNumber) { + return + } + calcMapCustomRange() + prop ? changeMisc(prop) : '' +} +const changeRangeItem = (prop, index) => { + console.log(state.legendForm.miscForm.mapLegendCustomRange[index]) + console.log(mapLegendCustomRangeCacheList[index]) + if (state.legendForm.miscForm.mapLegendCustomRange[index] === null) { + state.legendForm.miscForm.mapLegendCustomRange[index] = cloneDeep( + mapLegendCustomRangeCacheList[index] + ) + console.log(state.legendForm.miscForm.mapLegendCustomRange[index]) + } + changeMisc(prop) +} onMounted(() => { init() }) @@ -194,48 +291,58 @@ onMounted(() => { class="form-item" :class="'form-item-' + themes" :label="t('chart.legend')" + prop="miscForm.mapAutoLegend" > - {{ t('chart.margin_model_auto') }} - + + + 自定义 +
- - + + - - - - - - + 等分区间 + + + :effect="themes" + v-model="state.legendForm.miscForm.mapLegendRangeType" + :label="'custom'" + @change="changeLegendCustomType('mapLegendRangeType')" + > + 自定义区间 + @@ -254,8 +361,70 @@ onMounted(() => { :min="1" :max="9" :step="1" + :controls="true" controls-position="right" - @change="changeMisc('mapLegendNumber')" + @change="changeLegendNumber('mapLegendNumber')" + /> + + + +
+ + + + {{ index === 0 ? '最小值' : '' }} + {{ index === state.legendForm.miscForm.mapLegendNumber ? '最大值' : '' }} + + + + + + + + +
+ + + + + + + + + diff --git a/core/core-frontend/src/views/chart/components/editor/util/chart.ts b/core/core-frontend/src/views/chart/components/editor/util/chart.ts index f6857986ca..423c93ee27 100644 --- a/core/core-frontend/src/views/chart/components/editor/util/chart.ts +++ b/core/core-frontend/src/views/chart/components/editor/util/chart.ts @@ -275,6 +275,8 @@ export const DEFAULT_MISC: ChartMiscAttr = { mapLegendMax: 0, mapLegendMin: 0, mapLegendNumber: 9, + mapLegendRangeType: 'quantize', + mapLegendCustomRange: [], flowMapConfig: { lineConfig: { mapLineAnimate: true, diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/map/map.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/map/map.ts index a78bc08842..d86e817423 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/map/map.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/map/map.ts @@ -88,6 +88,12 @@ export class Map extends L7PlotChartView { if (!misc.mapAutoLegend && legend.show) { let minValue = misc.mapLegendMin let maxValue = misc.mapLegendMax + let legendNumber = 9 + if (misc.mapLegendRangeType === 'custom') { + maxValue = 0 + minValue = 0 + legendNumber = misc.mapLegendNumber + } getMaxAndMinValueByData(sourceData, 'value', maxValue, minValue, (max, min) => { maxValue = max minValue = min @@ -96,7 +102,7 @@ export class Map extends L7PlotChartView { data: { max: maxValue, min: minValue, - legendNumber: 9 + legendNumber: legendNumber } }) }) @@ -257,7 +263,8 @@ export class Map extends L7PlotChartView { options: ChoroplethOptions, _context: Record ): ChoroplethOptions { - const { basicStyle } = parseJson(chart.customAttr) + const { basicStyle, misc } = parseJson(chart.customAttr) + const colors = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha)) if (basicStyle.suspension === false && basicStyle.showZoom === undefined) { return options } @@ -282,7 +289,49 @@ export class Map extends L7PlotChartView { } const customLegend = { position: 'bottomleft', - customContent: (_: string, items: CategoryLegendListItem[]) => { + domStyles: { + 'l7plot-legend__category-value': { + fontSize: legend.fontSize + 'px', + color: legend.color + }, + 'l7plot-legend__category-marker': { + ...LEGEND_SHAPE_STYLE_MAP[legend.icon] + } + } + } + if (!misc.mapAutoLegend && misc.mapLegendRangeType === 'custom') { + // 获取图例区间数据 + const items = [] + // 区间数组 + const ranges = misc.mapLegendCustomRange + .slice(0, -1) + .map((item, index) => [item, misc.mapLegendCustomRange[index + 1]]) + ranges.forEach((range, index) => { + const tmpRange = [range[0]?.toFixed(0), range[1]?.toFixed(0)] + const colorIndex = index % colors.length + items.push({ + value: tmpRange, + color: colors[colorIndex] + }) + }) + customLegend['items'] = items + const findColorByValue = (value, intervals) => { + if (value) { + for (const interval of intervals) { + if (value >= interval.value[0] && value <= interval.value[1]) { + return interval.color + } + } + } + // 或者可以返回 undefined + return null + } + options.color.value = t => { + const c = findColorByValue(t.value, items) + return c ? c : null + } + } else { + customLegend['customContent'] = (_: string, items: CategoryLegendListItem[]) => { const showItems = items?.length > 30 ? items.slice(0, 30) : items if (showItems?.length) { const containerDom = createDom(CONTAINER_TPL) as HTMLElement @@ -311,15 +360,6 @@ export class Map extends L7PlotChartView { return listDom } return '' - }, - domStyles: { - 'l7plot-legend__category-value': { - fontSize: legend.fontSize + 'px', - color: legend.color - }, - 'l7plot-legend__category-marker': { - ...LEGEND_SHAPE_STYLE_MAP[legend.icon] - } } } defaultsDeep(options, { legend: customLegend }) diff --git a/core/core-frontend/src/views/chart/components/js/util.ts b/core/core-frontend/src/views/chart/components/js/util.ts index e189e030d8..fd6215287c 100644 --- a/core/core-frontend/src/views/chart/components/js/util.ts +++ b/core/core-frontend/src/views/chart/components/js/util.ts @@ -585,7 +585,7 @@ export const getDynamicColorScale = ( minValue: number, maxValue: number, intervals: number, - colors: string[] + colors?: string[] ) => { const step = (maxValue - minValue) / intervals @@ -593,8 +593,8 @@ export const getDynamicColorScale = ( for (let i = 0; i < intervals; i++) { colorScale.push({ value: [minValue + i * step, minValue + (i + 1) * step], - color: colors[i], - label: `${(minValue + i * step).toFixed(2)} - ${(minValue + (i + 1) * step).toFixed(2)}` + color: colors?.[i], + label: `${(minValue + i * step).toFixed(0)} - ${(minValue + (i + 1) * step).toFixed(0)}` }) }