ソースを参照

feat: 弹幕文字

蒋承 3 年 前
コミット
31e402f880

BIN
src/assets/images/chart/informations/text_barrage.gif


+ 42 - 0
src/packages/components/Informations/Texts/TextBarrage/config.ts

@@ -0,0 +1,42 @@
+import { PublicConfigClass } from '@/packages/public'
+import { CreateComponentType } from '@/packages/index.d'
+import { TextBarrageConfig } from './index'
+import { chartInitConfig } from '@/settings/designSetting'
+import cloneDeep from 'lodash/cloneDeep'
+
+export enum FontWeightEnum {
+  NORMAL = '常规',
+  BOLD = '加粗',
+}
+
+export const FontWeightObject = {
+  [FontWeightEnum.NORMAL]: 'normal',
+  [FontWeightEnum.BOLD]: 'bold',
+}
+
+export const option = {
+  
+  dataset: '让数字化看得见',
+  fontSize: 32,
+  fontColor: '#ffffff',
+  fontWeight: 'normal',
+  // 字间距
+  letterSpacing: 5,
+  //阴影
+  showShadow:  true,
+  boxShadow: 'none',
+  hShadow: 0,
+  vShadow: 0,
+  blurShadow: 8,
+  colorShadow: '#0075ff',
+  //动画
+  animationTime: 0,
+  animationSpeed: 50,
+}
+
+export default class Config extends PublicConfigClass implements CreateComponentType {
+  public key = TextBarrageConfig.key
+  public attr = { ...chartInitConfig, w: 500, h: 70, zIndex: -1 }
+  public chartConfig = cloneDeep(TextBarrageConfig)
+  public option = cloneDeep(option)
+}

+ 89 - 0
src/packages/components/Informations/Texts/TextBarrage/config.vue

@@ -0,0 +1,89 @@
+<template>
+  <collapse-item name="信息" :expanded="true">
+    <setting-item-box name="文字" :alone="true">
+      <setting-item>
+        <n-input v-model:value="optionData.dataset" size="small"></n-input>
+      </setting-item>
+    </setting-item-box>
+  </collapse-item>
+
+  <collapse-item name="样式" :expanded="true">
+    <setting-item-box name="文字">
+      <setting-item name="颜色">
+        <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.fontColor"></n-color-picker>
+      </setting-item>
+      <setting-item name="字体大小">
+        <n-input-number v-model:value="optionData.fontSize" size="small" placeholder="字体大小"></n-input-number>
+      </setting-item>
+      <setting-item name="字体粗细">
+        <n-select v-model:value="optionData.fontWeight" size="small" :options="fontWeightOptions" />
+      </setting-item>
+
+      <setting-item name="字间距">
+        <n-input-number v-model:value="optionData.letterSpacing" size="small" placeholder="输入字间距"></n-input-number>
+      </setting-item>
+    </setting-item-box>
+    <setting-item-box name="阴影">
+      <setting-item>
+        <n-space>
+          <n-switch v-model:value="optionData.showShadow" size="small" />
+          <n-text>展示阴影</n-text>
+        </n-space>
+      </setting-item>
+      <setting-item name="颜色">
+        <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.colorShadow"></n-color-picker
+      ></setting-item>
+      <setting-item name="x">
+        <n-input-number v-model:value="optionData.hShadow" size="small"></n-input-number
+      ></setting-item>
+      <setting-item name="y">
+        <n-input-number v-model:value="optionData.vShadow" size="small"></n-input-number
+      ></setting-item>
+      <setting-item name="模糊">
+        <n-input-number v-model:value="optionData.blurShadow" size="small"></n-input-number
+      ></setting-item>
+    </setting-item-box>
+
+    <setting-item-box name="动画">
+      <setting-item name="动画速度">
+        <n-input-number
+          v-model:value="optionData.animationSpeed"
+          size="small"
+          placeholder="动画速度"
+          :min="0"
+        ></n-input-number>
+      </setting-item>
+      <setting-item name="动画间隔">
+        <n-input-number
+          v-model:value="optionData.animationTime"
+          size="small"
+          placeholder="动画间隔"
+          :min="0"
+        ></n-input-number>
+      </setting-item>
+    </setting-item-box>
+  </collapse-item>
+</template>
+
+<script setup lang="ts">
+import { PropType } from 'vue'
+import { option, FontWeightEnum, FontWeightObject } from './config'
+import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
+const props = defineProps({
+  optionData: {
+    type: Object as PropType<typeof option>,
+    required: true
+  }
+})
+
+const fontWeightOptions = [
+  {
+    label: FontWeightEnum.NORMAL,
+    value: FontWeightObject[FontWeightEnum.NORMAL]
+  },
+  {
+    label: FontWeightEnum.BOLD,
+    value: FontWeightObject[FontWeightEnum.BOLD]
+  }
+]
+</script>

+ 14 - 0
src/packages/components/Informations/Texts/TextBarrage/index.ts

@@ -0,0 +1,14 @@
+import image from '@/assets/images/chart/informations/text_barrage.gif'
+import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
+import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
+
+export const TextBarrageConfig: ConfigType = {
+  key: 'TextBarrage',
+  chartKey: 'VTextBarrage',
+  conKey: 'VCTextBarrage',
+  title: '弹幕文字',
+  category: ChatCategoryEnum.TEXT,
+  categoryName: ChatCategoryEnumName.TEXT,
+  package: PackagesCategoryEnum.INFORMATIONS,
+  image
+}

+ 102 - 0
src/packages/components/Informations/Texts/TextBarrage/index.vue

@@ -0,0 +1,102 @@
+<template>
+  <div class="go-text-box">
+    <div class="content">
+      <span>
+        {{ option.dataset }}
+      </span>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { PropType, toRefs, shallowReactive, watch, computed, ref } from 'vue'
+import { CreateComponentType } from '@/packages/index.d'
+import { useChartDataFetch } from '@/hooks'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { option as configOption } from './config'
+import { values } from 'lodash'
+
+const props = defineProps({
+  chartConfig: {
+    type: Object as PropType<CreateComponentType & typeof option>,
+    required: true
+  }
+})
+
+const { w } = toRefs(props.chartConfig.attr)
+
+const { fontColor, fontSize, letterSpacing, fontWeight, animationTime, animationSpeed, boxShadow } = toRefs(
+  props.chartConfig.option
+)
+
+const option = shallowReactive({
+  dataset: configOption.dataset
+})
+
+// 手动更新
+watch(
+  () => props.chartConfig.option.dataset,
+  (newData: any) => {
+    option.dataset = newData
+  },
+  {
+    immediate: true,
+    deep: false
+  }
+)
+
+//阴影
+watch(
+  props.chartConfig.option,
+  () => {
+    try {
+      if (props.chartConfig.option.showShadow) {
+        boxShadow.value = `${props.chartConfig.option.hShadow}px ${props.chartConfig.option.vShadow}px ${props.chartConfig.option.blurShadow}px ${props.chartConfig.option.colorShadow}`
+      } else {
+        boxShadow.value = 'none'
+      }
+    } catch (error) {
+      console.log(error)
+    }
+  },
+  {
+    immediate: true
+  }
+)
+
+const transitionDuration = computed(() => {
+  return Math.floor((w.value as any) / (animationSpeed.value as any))
+})
+
+// 预览更新
+useChartDataFetch(props.chartConfig, useChartEditStore, (newData: string) => {
+  option.dataset = newData
+})
+</script>
+
+<style lang="scss" scoped>
+@include go('text-box') {
+  display: flex;
+  align-items: center;
+  .content {
+    width: 100%;
+    color: v-bind('fontColor');
+    font-size: v-bind('fontSize + "px"');
+    letter-spacing: v-bind('letterSpacing + "px"');
+    font-weight: v-bind('fontWeight');
+    text-shadow: v-bind('boxShadow');
+    position: absolute;
+    animation: barrage v-bind('transitionDuration + "s"') linear v-bind('animationTime + "s"') infinite;
+  }
+  @keyframes barrage {
+    from {
+      left: 100%;
+      transform: translateX(0);
+    }
+    to {
+      left: 0;
+      transform: translateX(-100%);
+    }
+  }
+}
+</style>

+ 2 - 1
src/packages/components/Informations/Texts/index.ts

@@ -1,4 +1,5 @@
 import { TextCommonConfig } from './TextCommon/index'
+import { TextBarrageConfig } from './TextBarrage/index'
 import { TextGradientConfig } from './TextGradient/index'
 
-export default [TextCommonConfig, TextGradientConfig]
+export default [TextCommonConfig, TextGradientConfig, TextBarrageConfig]