pipipi-pikachu пре 5 година
родитељ
комит
beee25590d

+ 68 - 0
src/components/Chart.vue

@@ -49,6 +49,12 @@ export default defineComponent({
     options: {
     options: {
       type: Object as PropType<ILineChartOptions & IBarChartOptions & IPieChartOptions>,
       type: Object as PropType<ILineChartOptions & IBarChartOptions & IPieChartOptions>,
     },
     },
+    themeColors: {
+      type: Array as PropType<string[]>,
+    },
+    gridColor: {
+      type: String,
+    },
   },
   },
   setup(props) {
   setup(props) {
     const chartRef = ref<HTMLElement | null>(null)
     const chartRef = ref<HTMLElement | null>(null)
@@ -93,6 +99,24 @@ export default defineComponent({
 
 
     onMounted(renderChart)
     onMounted(renderChart)
 
 
+    const updateTheme = () => {
+      if(!chartRef.value) return
+
+      if(props.themeColors) {
+        for(let i = 0; i < props.themeColors.length; i++) {
+          chartRef.value.style.setProperty(`--theme-color-${i + 1}`, props.themeColors[i])
+        }
+      }
+
+      if(props.gridColor) chartRef.value.style.setProperty(`--grid-color`, props.gridColor)
+    }
+
+    watch([
+      () => props.themeColors,
+      () => props.gridColor,
+    ], updateTheme)
+    onMounted(updateTheme)
+
     return {
     return {
       slideScale,
       slideScale,
       chartRef,
       chartRef,
@@ -105,4 +129,48 @@ export default defineComponent({
 .chart-content {
 .chart-content {
   transform-origin: 0 0;
   transform-origin: 0 0;
 }
 }
+</style>
+
+<style lang="scss">
+.chart-content {
+  $ct-series-names: (a, b, c, d);
+
+  --theme-color-1: #d70206;
+  --theme-color-2: #f05b4f;
+  --theme-color-3: #f4c63d;
+  --theme-color-4: #d17905;
+
+  @for $i from 1 to length($ct-series-names) {
+    $color: var(--theme-color-#{$i});
+
+    .ct-series-#{nth($ct-series-names, $i)} .ct-line {
+      stroke: $color;
+    }
+    .ct-series-#{nth($ct-series-names, $i)} .ct-point {
+      stroke: $color;
+    }
+    .ct-series-#{nth($ct-series-names, $i)} .ct-area {
+      fill: $color;
+    }
+    .ct-series-#{nth($ct-series-names, $i)} .ct-bar {
+      stroke: $color;
+    }
+    .ct-series-#{nth($ct-series-names, $i)} .ct-slice-pie {
+      fill: $color;
+    }
+    .ct-series-#{nth($ct-series-names, $i)} .ct-slice-donut {
+      stroke: $color;
+    }
+  }
+
+  --grid-color: rgba(0, 0, 0, 0.4);
+
+  .ct-grid {
+    stroke: var(--grid-color);
+  }
+  .ct-label {
+    fill: var(--grid-color);
+    color: var(--grid-color);
+  }
+}
 </style>
 </style>

+ 10 - 0
src/configs/chartTheme.ts

@@ -0,0 +1,10 @@
+export const CHART_THEME_COLORS = [
+  ['#d70206', '#f05b4f', '#f4c63d', '#d17905'],
+  ['#67d5b5', '#ee7785', '#c89ec4', '#84b1ed'],
+  ['#f6ea8c', '#f26d5b', '#c03546', '#492540'],
+  ['#583d72', '#9f5f80', '#ffba93', '#ff8e71'],
+  ['#59886b', '#c05555', '#ffc85c', '#fff8c1'],
+  ['#d87c7c', '#919e8b', '#d7ab82', '#6e7074'],
+  ['#1a1a2e', '#16213e', '#0f3460', '#e94560'],
+  ['#e01f54', '#001852', '#f5e8c8', '#b8d2c7'],
+]

+ 2 - 0
src/types/slides.ts

@@ -126,6 +126,8 @@ export interface PPTChartElement {
   data: ChartData;
   data: ChartData;
   options?: ILineChartOptions & IBarChartOptions & IPieChartOptions;
   options?: ILineChartOptions & IBarChartOptions & IPieChartOptions;
   outline?: PPTElementOutline;
   outline?: PPTElementOutline;
+  themeColors?: string[];
+  gridColor?: string;
 }
 }
 
 
 export interface TableElementCell {
 export interface TableElementCell {

+ 119 - 0
src/views/Editor/Toolbar/ElementStylePanel/ChartStylePanel/index.vue

@@ -51,6 +51,51 @@
         <ColorButton :color="fill" style="flex: 3;" />
         <ColorButton :color="fill" style="flex: 3;" />
       </Popover>
       </Popover>
     </div>
     </div>
+    <div class="row">
+      <div style="flex: 2;">主题配色:</div>
+      <Popover trigger="click" v-model:visible="themePoolVisible">
+        <template #content>
+          <div class="theme-pool">
+            <div 
+              class="theme-item" 
+              v-for="(theme, index) in CHART_THEME_COLORS" 
+              :key="index"
+              @click="updateTheme(theme)"
+            >
+              <div 
+                class="color-block" 
+                v-for="(color, index) in theme" 
+                :key="index"
+                :style="{ backgroundColor: color }"
+              ></div>
+            </div>
+          </div>
+        </template>
+        <Button class="theme-color-btn" style="flex: 3;">
+          <div class="theme-color-content">
+            <div 
+              class="color-block" 
+              v-for="(color, index) in themeColors" 
+              :key="index"
+              :style="{ backgroundColor: color }"
+            ></div>
+          </div>
+          <IconPlatte class="theme-color-btn-icon" />
+        </Button>
+      </Popover>
+    </div>
+    <div class="row">
+      <div style="flex: 2;">网格颜色:</div>
+      <Popover trigger="click">
+        <template #content>
+          <ColorPicker
+            :modelValue="gridColor"
+            @update:modelValue="value => updateGridColor(value)"
+          />
+        </template>
+        <ColorButton :color="gridColor" style="flex: 3;" />
+      </Popover>
+    </div>
 
 
     <Divider />
     <Divider />
     <ElementOutline />
     <ElementOutline />
@@ -78,6 +123,7 @@ import { IBarChartOptions, ILineChartOptions, IPieChartOptions } from 'chartist'
 import { useStore } from 'vuex'
 import { useStore } from 'vuex'
 import { MutationTypes, State } from '@/store'
 import { MutationTypes, State } from '@/store'
 import { ChartData, PPTChartElement } from '@/types/slides'
 import { ChartData, PPTChartElement } from '@/types/slides'
+import { CHART_THEME_COLORS } from '@/configs/chartTheme'
 import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 import useHistorySnapshot from '@/hooks/useHistorySnapshot'
 
 
 import ElementOutline from '../../common/ElementOutline.vue'
 import ElementOutline from '../../common/ElementOutline.vue'
@@ -96,11 +142,15 @@ export default defineComponent({
     const handleElement: Ref<PPTChartElement> = computed(() => store.getters.handleElement)
     const handleElement: Ref<PPTChartElement> = computed(() => store.getters.handleElement)
 
 
     const chartDataEditorVisible = ref(false)
     const chartDataEditorVisible = ref(false)
+    const themePoolVisible = ref(false)
 
 
     const { addHistorySnapshot } = useHistorySnapshot()
     const { addHistorySnapshot } = useHistorySnapshot()
 
 
     const fill = ref<string>()
     const fill = ref<string>()
 
 
+    const themeColors = ref<string[]>([])
+    const gridColor = ref('')
+
     const lineSmooth = ref<boolean | Function>(true)
     const lineSmooth = ref<boolean | Function>(true)
     const showLine = ref(true)
     const showLine = ref(true)
     const showArea = ref(false)
     const showArea = ref(false)
@@ -126,6 +176,9 @@ export default defineComponent({
         if(_horizontalBars !== undefined) horizontalBars.value = _horizontalBars
         if(_horizontalBars !== undefined) horizontalBars.value = _horizontalBars
         if(_donut !== undefined) donut.value = _donut
         if(_donut !== undefined) donut.value = _donut
       }
       }
+
+      themeColors.value = handleElement.value.themeColors || CHART_THEME_COLORS[0]
+      gridColor.value = handleElement.value.gridColor || 'rgba(0, 0, 0, 0.4)'
     }, { deep: true, immediate: true })
     }, { deep: true, immediate: true })
 
 
     const updateData = (data: ChartData) => {
     const updateData = (data: ChartData) => {
@@ -149,8 +202,22 @@ export default defineComponent({
       addHistorySnapshot()
       addHistorySnapshot()
     }
     }
 
 
+    const updateTheme = (themeColors: string[]) => {
+      themePoolVisible.value = false
+      const props = { themeColors }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
+    }
+
+    const updateGridColor = (gridColor: string) => {
+      const props = { gridColor }
+      store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
+      addHistorySnapshot()
+    }
+
     return {
     return {
       chartDataEditorVisible,
       chartDataEditorVisible,
+      themePoolVisible,
       handleElement,
       handleElement,
       updateData,
       updateData,
       fill,
       fill,
@@ -161,6 +228,11 @@ export default defineComponent({
       horizontalBars,
       horizontalBars,
       donut,
       donut,
       updateOptions,
       updateOptions,
+      themeColors,
+      gridColor,
+      CHART_THEME_COLORS,
+      updateTheme,
+      updateGridColor,
     }
     }
   },
   },
 })
 })
@@ -179,4 +251,51 @@ export default defineComponent({
 .btn-icon {
 .btn-icon {
   margin-right: 3px;
   margin-right: 3px;
 }
 }
+
+.theme-item {
+  border-radius: $borderRadius;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 5px 20px;
+  transition: background-color .1s;
+
+  & + .theme-item {
+    margin-top: 8px;
+  }
+
+  &:hover {
+    background-color: #e1e1e1;
+    cursor: pointer;
+  }
+}
+.theme-color-btn {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  padding: 0 !important;
+}
+.theme-color-content {
+  height: 20px;
+  margin-left: 8px;
+  flex: 1;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.color-block {
+  width: 18px;
+  height: 18px;
+  border-radius: 50%;
+
+  & + .color-block {
+    margin-left: -3px;
+  }
+}
+.theme-color-btn-icon {
+  width: 30px;
+  font-size: 12px;
+  margin-top: 2px;
+  color: #bfbfbf;
+}
 </style>
 </style>

+ 8 - 3
src/views/components/element/ChartElement/BaseChartElement.vue

@@ -18,9 +18,9 @@
         :height="elementInfo.height"
         :height="elementInfo.height"
         :outline="elementInfo.outline"
         :outline="elementInfo.outline"
       />
       />
-      <IconChartLine fill="#d70206" strokeWidth="2" :size="size" v-if="elementInfo.chartType === 'line'" />
-      <IconChartHistogram fill="#d70206" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'bar'" />
-      <IconChartProportion fill="#d70206" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'pie'" />
+      <IconChartLine :fill="color" strokeWidth="2" :size="size" v-if="elementInfo.chartType === 'line'" />
+      <IconChartHistogram :fill="color" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'bar'" />
+      <IconChartProportion :fill="color" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'pie'" />
     </div>
     </div>
   </div>
   </div>
 </template>
 </template>
@@ -28,6 +28,7 @@
 <script lang="ts">
 <script lang="ts">
 import { computed, defineComponent, PropType } from 'vue'
 import { computed, defineComponent, PropType } from 'vue'
 import { PPTChartElement } from '@/types/slides'
 import { PPTChartElement } from '@/types/slides'
+import { CHART_THEME_COLORS } from '@/configs/chartTheme'
 
 
 import ElementOutline from '@/views/components/element/ElementOutline.vue'
 import ElementOutline from '@/views/components/element/ElementOutline.vue'
 
 
@@ -44,9 +45,13 @@ export default defineComponent({
   },
   },
   setup(props) {
   setup(props) {
     const size = computed(() => Math.min(props.elementInfo.width, props.elementInfo.height))
     const size = computed(() => Math.min(props.elementInfo.width, props.elementInfo.height))
+    const color = computed(() => {
+      return props.elementInfo.themeColors ? props.elementInfo.themeColors[0] : CHART_THEME_COLORS[0][0]
+    })
 
 
     return {
     return {
       size,
       size,
+      color,
     }
     }
   },
   },
 })
 })

+ 2 - 0
src/views/components/element/ChartElement/ScreenChartElement.vue

@@ -24,6 +24,8 @@
         :type="elementInfo.chartType"
         :type="elementInfo.chartType"
         :data="elementInfo.data"
         :data="elementInfo.data"
         :options="elementInfo.options"
         :options="elementInfo.options"
+        :themeColors="elementInfo.themeColors"
+        :gridColor="elementInfo.gridColor"
       />
       />
     </div>
     </div>
   </div>
   </div>

+ 2 - 0
src/views/components/element/ChartElement/index.vue

@@ -27,6 +27,8 @@
         :type="elementInfo.chartType"
         :type="elementInfo.chartType"
         :data="elementInfo.data"
         :data="elementInfo.data"
         :options="elementInfo.options"
         :options="elementInfo.options"
+        :themeColors="elementInfo.themeColors"
+        :gridColor="elementInfo.gridColor"
       />
       />
     </div>
     </div>
   </div>
   </div>