Explorar el Código

feat: 优化胶囊图,新增配置

奔跑的面条 hace 3 años
padre
commit
f6af081806

BIN
src/assets/images/chart/charts/capsule.png


+ 8 - 6
src/packages/components/Charts/Mores/CapsuleChart/config.ts → src/packages/components/Charts/Bars/CapsuleChart/config.ts

@@ -1,4 +1,4 @@
-import {  PublicConfigClass } from '@/packages/public'
+import { PublicConfigClass } from '@/packages/public'
 import { CapsuleChartConfig } from './index'
 import { CreateComponentType } from '@/packages/index.d'
 import { chartInitConfig } from '@/settings/designSetting'
@@ -6,18 +6,20 @@ import { chartInitConfig } from '@/settings/designSetting'
 import cloneDeep from 'lodash/cloneDeep'
 import dataJson from './data.json'
 
-
 export const option = {
-  dataset:dataJson,
-  colors: ['#e062ae', '#fb7293', '#e690d1', '#32c5e9', '#96bfff'],
+  dataset: dataJson,
+  colors: ['#c4ebad', '#6be6c1', '#a0a7e6', '#96dee8', '#3fb1e3' ],
   unit: '',
-  itemHeight:10,
+  itemHeight: 10,
+  valueFontSize: 16,
+  paddingRight: 50,
+  paddingLeft: 50,
   showValue: true
 }
 
 export default class Config extends PublicConfigClass implements CreateComponentType {
   public key: string = CapsuleChartConfig.key
-  public attr = { ...chartInitConfig,w: 300, h: 200 ,zIndex: -1}
+  public attr = { ...chartInitConfig, zIndex: -1 }
   public chartConfig = cloneDeep(CapsuleChartConfig)
   public option = cloneDeep(option)
 }

+ 53 - 0
src/packages/components/Charts/Bars/CapsuleChart/config.vue

@@ -0,0 +1,53 @@
+<template>
+  <!-- Echarts 全局设置 -->
+  <global-setting :optionData="optionData"> </global-setting>
+  <!-- 胶囊柱图 -->
+  <collapse-item name="胶囊柱图" expanded>
+    <SettingItemBox name="布局">
+      <setting-item name="左侧边距">
+        <n-input-number v-model:value="optionData.paddingLeft" :min="10" :step="1" size="small"></n-input-number>
+      </setting-item>
+      <setting-item name="右侧边距">
+        <n-input-number v-model:value="optionData.paddingRight" :min="10" :step="1" size="small"></n-input-number>
+      </setting-item>
+      <setting-item name="每块高度(px)">
+        <n-input-number v-model:value="optionData.itemHeight" :min="0" :step="1" size="small"></n-input-number>
+      </setting-item>
+    </SettingItemBox>
+    <SettingItemBox name="文本">
+      <setting-item name="所有文字大小">
+        <n-input-number v-model:value="optionData.valueFontSize" :min="0" :step="1" size="small"></n-input-number>
+      </setting-item>
+      <setting-item name="单位">
+        <n-input v-model:value="optionData.unit" size="small"></n-input>
+      </setting-item>
+
+      <SettingItem>
+        <n-space>
+          <n-switch v-model:value="optionData.showValue" size="small"></n-switch>
+          <n-text>显示数值</n-text>
+        </n-space>
+      </SettingItem>
+    </SettingItemBox>
+    <SettingItemBox name="颜色">
+      <setting-item v-for="(item, index) in optionData.colors" :key="index" :name="`颜色${index}`">
+        <n-color-picker v-model:value="optionData.colors[index]" size="small"></n-color-picker>
+      </setting-item>
+    </SettingItemBox>
+  </collapse-item>
+</template>
+
+<script setup lang="ts">
+import { PropType, computed } from 'vue'
+import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
+import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
+
+import { option } from './config'
+
+const props = defineProps({
+  optionData: {
+    type: Object as PropType<typeof option & GlobalThemeJsonType>,
+    required: true
+  }
+})
+</script>

+ 1 - 1
src/packages/components/Charts/Mores/CapsuleChart/data.json → src/packages/components/Charts/Bars/CapsuleChart/data.json

@@ -3,7 +3,7 @@
   "source": [
     { "name": "厦门", "value": 20 },
     { "name": "南阳", "value": 40 },
-    { "name": "背景", "value": 60 },
+    { "name": "北京", "value": 60 },
     { "name": "上海", "value": 80 },
     { "name": "新疆", "value": 100 }
   ]

+ 2 - 2
src/packages/components/Charts/Mores/CapsuleChart/index.ts → src/packages/components/Charts/Bars/CapsuleChart/index.ts

@@ -7,8 +7,8 @@ export const CapsuleChartConfig: ConfigType = {
   chartKey: 'VCapsuleChart',
   conKey: 'VCCapsuleChart',
   title: '胶囊柱图',
-  category: ChatCategoryEnum.MORE,
-  categoryName: ChatCategoryEnumName.MORE,
+  category: ChatCategoryEnum.BAR,
+  categoryName: ChatCategoryEnumName.BAR,
   package: PackagesCategoryEnum.CHARTS,
   chartFrame: ChartFrameEnum.COMMON,
   image

+ 228 - 223
src/packages/components/Charts/Mores/CapsuleChart/index.vue → src/packages/components/Charts/Bars/CapsuleChart/index.vue

@@ -1,223 +1,228 @@
-<script setup lang="ts">
-import { onMounted, watch, reactive,PropType } from 'vue'
-import merge from 'lodash/merge'
-import cloneDeep from 'lodash/cloneDeep'
-import { useChartDataFetch } from '@/hooks'
-import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
-import config from './config'
-
-const props = defineProps({
-  chartConfig: {
-    type: Object as PropType<config>,
-    default: () => ({})
-  }
-})
-type DataProps = {
-  name: string | number
-  value: string | number
-  [key: string]: string | number
-}
-
-interface StateProps {
-  defaultConfig: {
-    dataset: {
-      dimensions: Array<string>
-      source: Array<DataProps>
-    }
-    colors: Array<string>
-    unit: string
-    showValue: boolean
-    itemHeight: number
-  }
-  mergedConfig: any
-  capsuleLength: Array<number>
-  capsuleValue: Array<string | Object>
-  labelData: Array<number>
-  capsuleItemHeight: string
-}
-
-const state = reactive<StateProps>({
-  defaultConfig: {
-    dataset: { dimensions: ['name', 'value'], source: [] },
-    colors: ['#37a2da', '#32c5e9', '#67e0e3', '#9fe6b8', '#ffdb5c', '#ff9f7f', '#fb7293'],
-    unit: '',
-    showValue: false,
-    itemHeight: 10
-  },
-  mergedConfig: null,
-  capsuleLength: [],
-  capsuleValue: [],
-  labelData: [],
-  capsuleItemHeight: ''
-})
-
-watch(
-  () => props.chartConfig.option,
-  newVal => {
-    calcData(newVal)
-  },
-  {
-    deep: true
-  }
-)
-
-function calcData(data:any) {
-  mergeConfig(props.chartConfig.option)
-
-  calcCapsuleLengthAndLabelData()
-}
-
-function mergeConfig(data:any) {
-  state.mergedConfig = merge(cloneDeep(state.defaultConfig), data || {})
-}
-
-function calcCapsuleLengthAndLabelData() {
-  const { source } = state.mergedConfig.dataset
-  if (!source.length) return
-
-  state.capsuleItemHeight = handle(state.mergedConfig.itemHeight)
-  const capsuleValue = source.map((item: DataProps) => item[state.mergedConfig.dataset.dimensions[1]])
-
-  const maxValue = Math.max(...capsuleValue)
-
-  state.capsuleValue = capsuleValue
-
-  state.capsuleLength = capsuleValue.map((v: any) => (maxValue ? v / maxValue : 0))
-
-  const oneFifth = maxValue / 5
-
-  const labelData = Array.from(new Set(new Array(6).fill(0).map((v, i) => Math.ceil(i * oneFifth))))
-
-  state.labelData = labelData
-}
-const handle = (val: string | number) => {
-  return val + 'px'
-}
-onMounted(() => {
-  calcData(props.chartConfig.option)
-})
-
-// 预览
-useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
-    calcData(newData)
-})
-</script>
-<template>
-  <div class="dv-capsule-chart">
-    <template v-if="state.mergedConfig">
-      <div class="label-column">
-        <div
-          v-for="item in state.mergedConfig.dataset.source"
-          :key="item[state.mergedConfig.dataset.dimensions[0]]"
-          :style="{ height: state.capsuleItemHeight, lineHeight: state.capsuleItemHeight }"
-        >
-          {{ item[state.mergedConfig.dataset.dimensions[0]] }}
-        </div>
-        <div class="laset">&nbsp;</div>
-      </div>
-
-      <div class="capsule-container">
-        <div
-          v-for="(capsule, index) in state.capsuleLength"
-          :key="index"
-          class="capsule-item"
-          :style="{ height: state.capsuleItemHeight }"
-        >
-          <div
-            class="capsule-item-column"
-            :style="`width: ${capsule * 100}%; background-color: ${
-              state.mergedConfig.colors[index % state.mergedConfig.colors.length]
-            };height:calc(100% - ${2}px);`"
-          >
-            <div v-if="state.mergedConfig.showValue" class="capsule-item-value">
-              {{ state.capsuleValue[index] }}
-            </div>
-          </div>
-        </div>
-
-        <div class="unit-label">
-          <div v-for="(label, index) in state.labelData" :key="label + index">
-            {{ label }}
-          </div>
-        </div>
-      </div>
-
-      <div v-if="state.mergedConfig.unit" class="unit-text">
-        {{ state.mergedConfig.unit }}
-      </div>
-    </template>
-  </div>
-</template>
-
-<style lang="scss" scoped>
-.dv-capsule-chart {
-  position: relative;
-  display: flex;
-  flex-direction: row;
-  box-sizing: border-box;
-  padding: 10px 16px 10px 10px;
-  color: #fff;
-
-  .label-column {
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-    box-sizing: border-box;
-    padding-right: 10px;
-    text-align: right;
-    font-size: 12px;
-    >div:not(:last-child){
-        margin: 5px 0;
-    }
- 
-  }
-
-  .capsule-container {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    justify-content: space-between;
-  }
-
-  .capsule-item {
-    box-shadow: 0 0 3px #999;
-    height: 10px;
-    margin: 5px 0px;
-    border-radius: 5px;
-
-    .capsule-item-column {
-      position: relative;
-      height: 8px;
-      margin-top: 1px;
-      border-radius: 5px;
-      transition: all 0.3s;
-      display: flex;
-      justify-content: flex-end;
-      align-items: center;
-
-      .capsule-item-value {
-        font-size: 12px;
-        transform: translateX(100%);
-      }
-    }
-  }
-
-  .unit-label {
-    height: 20px;
-    font-size: 12px;
-    position: relative;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-  }
-
-  .unit-text {
-    text-align: right;
-    display: flex;
-    align-items: flex-end;
-    font-size: 12px;
-    line-height: 20px;
-    margin-left: 10px;
-  }
-}
-</style>
+<template>
+  <div
+    v-if="state.mergedConfig"
+    class="go-dv-capsule-chart"
+    :style="{ 
+      fontSize: numberSizeHandle(state.mergedConfig.valueFontSize),
+      paddingLeft: numberSizeHandle(state.mergedConfig.paddingLeft),
+      paddingRight: numberSizeHandle(state.mergedConfig.paddingRight)
+    }"
+  >
+    <div class="label-column">
+      <div
+        v-for="item in state.mergedConfig.dataset.source"
+        :key="item[state.mergedConfig.dataset.dimensions[0]]"
+        :style="{ height: state.capsuleItemHeight, lineHeight: state.capsuleItemHeight }"
+      >
+        {{ item[state.mergedConfig.dataset.dimensions[0]] }}
+      </div>
+      <div class="laset">&nbsp;</div>
+    </div>
+
+    <div class="capsule-container">
+      <div
+        v-for="(capsule, index) in state.capsuleLength"
+        :key="index"
+        class="capsule-item"
+        :style="{ height: state.capsuleItemHeight }"
+      >
+        <div
+          class="capsule-item-column"
+          :style="`width: ${capsule * 100}%; background-color: ${
+            state.mergedConfig.colors[index % state.mergedConfig.colors.length]
+          };height:calc(100% - ${2}px);`"
+        >
+          <div v-if="state.mergedConfig.showValue" class="capsule-item-value">
+            {{ state.capsuleValue[index] }}
+          </div>
+        </div>
+      </div>
+
+      <div class="unit-label">
+        <div v-for="(label, index) in state.labelData" :key="label + index">
+          {{ label }}
+        </div>
+      </div>
+    </div>
+
+    <div v-if="state.mergedConfig.unit" class="unit-text">
+      {{ state.mergedConfig.unit }}
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onMounted, watch, reactive, PropType } from 'vue'
+import merge from 'lodash/merge'
+import cloneDeep from 'lodash/cloneDeep'
+import { useChartDataFetch } from '@/hooks'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import config, { option } from './config'
+
+type DataProps = {
+  name: string | number
+  value: string | number
+  [key: string]: string | number
+}
+
+interface StateProps {
+  defaultConfig: {
+    dataset: {
+      dimensions: Array<string>
+      source: Array<DataProps>
+    }
+    colors: Array<string>
+    unit: string
+    showValue: boolean
+    itemHeight: number
+    valueFontSize: number
+    paddingLeft: number
+    paddingRight: number
+  }
+  mergedConfig: any
+  capsuleLength: Array<number>
+  capsuleValue: Array<string | Object>
+  labelData: Array<number>
+  capsuleItemHeight: string
+}
+
+const props = defineProps({
+  chartConfig: {
+    type: Object as PropType<config>,
+    default: () => ({})
+  }
+})
+
+const state = reactive<StateProps>({
+  defaultConfig: option,
+  mergedConfig: null,
+  capsuleLength: [],
+  capsuleValue: [],
+  labelData: [],
+  capsuleItemHeight: ''
+})
+
+watch(
+  () => props.chartConfig.option,
+  newVal => {
+    calcData(newVal)
+  },
+  {
+    deep: true
+  }
+)
+
+const calcData = (data: any) => {
+  mergeConfig(props.chartConfig.option)
+
+  calcCapsuleLengthAndLabelData()
+}
+
+const mergeConfig = (data: any) => {
+  state.mergedConfig = merge(cloneDeep(state.defaultConfig), data || {})
+}
+
+// 数据解析
+const calcCapsuleLengthAndLabelData = () => {
+  const { source } = state.mergedConfig.dataset
+  if (!source.length) return
+
+  state.capsuleItemHeight = numberSizeHandle(state.mergedConfig.itemHeight)
+  const capsuleValue = source.map((item: DataProps) => item[state.mergedConfig.dataset.dimensions[1]])
+
+  const maxValue = Math.max(...capsuleValue)
+
+  state.capsuleValue = capsuleValue
+
+  state.capsuleLength = capsuleValue.map((v: any) => (maxValue ? v / maxValue : 0))
+
+  const oneFifth = maxValue / 5
+
+  const labelData = Array.from(new Set(new Array(6).fill(0).map((v, i) => Math.ceil(i * oneFifth))))
+
+  state.labelData = labelData
+}
+
+const numberSizeHandle = (val: string | number) => {
+  return val + 'px'
+}
+
+onMounted(() => {
+  calcData(props.chartConfig.option)
+})
+
+// 预览
+useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
+  calcData(newData)
+})
+</script>
+
+<style lang="scss" scoped>
+@include go('dv-capsule-chart') {
+  position: relative;
+  display: flex;
+  flex-direction: row;
+  box-sizing: border-box;
+  padding: 20px;
+  padding-right: 50px;
+  color: #b9b8cc;
+
+  .label-column {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    box-sizing: border-box;
+    padding-right: 10px;
+    text-align: right;
+    > div:not(:last-child) {
+      margin: 5px 0;
+    }
+  }
+
+  .capsule-container {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+  }
+
+  .capsule-item {
+    box-shadow: 0 0 3px #999;
+    height: 10px;
+    margin: 5px 0px;
+    border-radius: 5px;
+
+    .capsule-item-column {
+      position: relative;
+      height: 8px;
+      margin-top: 1px;
+      border-radius: 5px;
+      transition: all 0.3s;
+      display: flex;
+      justify-content: flex-end;
+      align-items: center;
+
+      .capsule-item-value {
+        padding-left: 10px;
+        transform: translateX(100%);
+      }
+    }
+  }
+
+  .unit-label {
+    height: 20px;
+    position: relative;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+
+  .unit-text {
+    text-align: right;
+    display: flex;
+    align-items: flex-end;
+    line-height: 20px;
+    margin-left: 10px;
+  }
+}
+</style>

+ 2 - 1
src/packages/components/Charts/Bars/index.ts

@@ -1,4 +1,5 @@
 import { BarCommonConfig } from './BarCommon/index'
 import { BarCrossrangeConfig } from './BarCrossrange/index'
+import { CapsuleChartConfig } from './CapsuleChart/index'
 
-export default [BarCommonConfig, BarCrossrangeConfig]
+export default [BarCommonConfig, BarCrossrangeConfig, CapsuleChartConfig]

+ 0 - 43
src/packages/components/Charts/Mores/CapsuleChart/config.vue

@@ -1,43 +0,0 @@
-<template>
-  <!-- Echarts 全局设置 -->
-  <global-setting :optionData="optionData"> </global-setting>
-  <!-- 胶囊柱图 -->
-  <collapse-item :name="`胶囊柱图`" expanded>
-    <SettingItemBox name="指标">
-      <SettingItem name="显示数值">
-        <n-space>
-          <n-switch v-model:value="optionData.showValue" size="small"></n-switch>
-        </n-space>
-      </SettingItem>
-      <setting-item name="单位">
-        
-        <n-input v-model:value="optionData.unit" size="small"></n-input>
-      </setting-item>
-      <setting-item name="每块高度(px)">
-        <n-input-number
-          v-model:value="optionData.itemHeight"
-          :min="0"
-          :step="1"
-          size="small"
-          placeholder="水球数值"
-        ></n-input-number>
-      </setting-item>
-    </SettingItemBox>
-  </collapse-item>
-</template>
-
-<script setup lang="ts">
-import { PropType, computed } from 'vue'
-import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
-import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
-
-import { option } from './config'
-
-const props = defineProps({
-  optionData: {
-    type: Object as PropType<typeof option & GlobalThemeJsonType>,
-    required: true
-  }
-})
-
-</script>

+ 1 - 3
src/packages/components/Charts/Mores/index.ts

@@ -4,7 +4,5 @@ import { FunnelConfig } from './Funnel/index'
 import { HeatmapConfig } from './Heatmap/index'
 import { WaterPoloConfig } from './WaterPolo/index'
 import { TreeMapConfig } from './TreeMap/index'
-import { CapsuleChartConfig } from './CapsuleChart'
 
-
-export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig,CapsuleChartConfig]
+export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig]