|
@@ -1,43 +1,52 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="text-style-panel">
|
|
<div class="text-style-panel">
|
|
|
<ElementPosition/>
|
|
<ElementPosition/>
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
<el-row>
|
|
<el-row>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-select v-model="elementFontFamily" placement="left" @change="handleElementFontFamily">
|
|
<el-select v-model="elementFontFamily" placement="left" @change="handleElementFontFamily">
|
|
|
<el-option-group v-for="group in fontOptionGroups" :key="group.label" :label="group.label">
|
|
<el-option-group v-for="group in fontOptionGroups" :key="group.label" :label="group.label">
|
|
|
- <el-option v-for="item in group.options" :key="item" :value="item.value" :label="item.label" :style="{fontFamily: item.value}"></el-option>
|
|
|
|
|
|
|
+ <template v-if="group.type == 0">
|
|
|
|
|
+ <el-option v-for="item in group.options" :key="item" :value="item.value" :label="item.label"
|
|
|
|
|
+ :style="{fontFamily: item.value}"></el-option>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <template v-else>
|
|
|
|
|
+ <el-option v-for="item in group.options" :key="item.id" :value="item.fontName" :label="item.fontName">
|
|
|
|
|
+ <el-image style="height: 18px; width: 90px" :src="item.fontThumbUrl"></el-image>
|
|
|
|
|
+ </el-option>
|
|
|
|
|
+ </template>
|
|
|
</el-option-group>
|
|
</el-option-group>
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
- <el-select
|
|
|
|
|
- v-model="handleElement.fontSize"
|
|
|
|
|
- filterable
|
|
|
|
|
- allow-create
|
|
|
|
|
- default-first-option
|
|
|
|
|
- :filterMethod="handleElementInputSize"
|
|
|
|
|
- placement="left"
|
|
|
|
|
- @change="handleElementFontSize"
|
|
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="handleElement.fontSize"
|
|
|
|
|
+ filterable
|
|
|
|
|
+ allow-create
|
|
|
|
|
+ default-first-option
|
|
|
|
|
+ :filterMethod="handleElementInputSize"
|
|
|
|
|
+ placement="left"
|
|
|
|
|
+ @change="handleElementFontSize"
|
|
|
>
|
|
>
|
|
|
<el-option v-for="item in FontSizeLibs" :key="item" :label="item" :value="item"></el-option>
|
|
<el-option v-for="item in FontSizeLibs" :key="item" :label="item" :value="item"></el-option>
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
- </el-row>
|
|
|
|
|
-
|
|
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+
|
|
|
<el-row class="mt-10">
|
|
<el-row class="mt-10">
|
|
|
<el-col :span="6">
|
|
<el-col :span="6">
|
|
|
- <el-tooltip placement="top" content="文字颜色" :hide-after="0" >
|
|
|
|
|
|
|
+ <el-tooltip placement="top" content="文字颜色" :hide-after="0">
|
|
|
<div @click.stop class="tooltip-popover">
|
|
<div @click.stop class="tooltip-popover">
|
|
|
<el-popover trigger="click" placement="bottom" :width="265" @click.stop>
|
|
<el-popover trigger="click" placement="bottom" :width="265" @click.stop>
|
|
|
<template #reference>
|
|
<template #reference>
|
|
|
<el-button class="font-color">
|
|
<el-button class="font-color">
|
|
|
<TextColorButton :color="handleElement.color">
|
|
<TextColorButton :color="handleElement.color">
|
|
|
- <IconText />
|
|
|
|
|
|
|
+ <IconText/>
|
|
|
</TextColorButton>
|
|
</TextColorButton>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</template>
|
|
</template>
|
|
|
- <ColorPicker :modelValue="handleElement.color" @update:modelValue="(color: string) => updateFontColor(color)"/>
|
|
|
|
|
|
|
+ <ColorPicker :modelValue="handleElement.color"
|
|
|
|
|
+ @update:modelValue="(color: string) => updateFontColor(color)"/>
|
|
|
</el-popover>
|
|
</el-popover>
|
|
|
</div>
|
|
</div>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
@@ -49,11 +58,12 @@
|
|
|
<template #reference>
|
|
<template #reference>
|
|
|
<el-button class="high-light">
|
|
<el-button class="high-light">
|
|
|
<TextColorButton :color="elementBackgrounColor">
|
|
<TextColorButton :color="elementBackgrounColor">
|
|
|
- <IconHighLight />
|
|
|
|
|
|
|
+ <IconHighLight/>
|
|
|
</TextColorButton>
|
|
</TextColorButton>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</template>
|
|
</template>
|
|
|
- <ColorPicker :modelValue="elementBackgrounColor" @update:modelValue="(color: string) => updateBackgroundColor(color)"/>
|
|
|
|
|
|
|
+ <ColorPicker :modelValue="elementBackgrounColor"
|
|
|
|
|
+ @update:modelValue="(color: string) => updateBackgroundColor(color)"/>
|
|
|
</el-popover>
|
|
</el-popover>
|
|
|
</div>
|
|
</div>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
@@ -62,13 +72,15 @@
|
|
|
<el-button-group class="full-group">
|
|
<el-button-group class="full-group">
|
|
|
<el-tooltip placement="top" content="增大字号" :hide-after="0">
|
|
<el-tooltip placement="top" content="增大字号" :hide-after="0">
|
|
|
<el-button class="font-size" @click="handleElementFontsize('+')">
|
|
<el-button class="font-size" @click="handleElementFontsize('+')">
|
|
|
- <IconFontSize />+
|
|
|
|
|
|
|
+ <IconFontSize/>
|
|
|
|
|
+ +
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
|
|
|
|
|
<el-tooltip placement="top" content="减小字号" :hide-after="0">
|
|
<el-tooltip placement="top" content="减小字号" :hide-after="0">
|
|
|
<el-button @click="handleElementFontsize('-')">
|
|
<el-button @click="handleElementFontsize('-')">
|
|
|
- <IconFontSize />-
|
|
|
|
|
|
|
+ <IconFontSize/>
|
|
|
|
|
+ -
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
</el-button-group>
|
|
</el-button-group>
|
|
@@ -79,22 +91,22 @@
|
|
|
<div class="full-checkbox">
|
|
<div class="full-checkbox">
|
|
|
<el-tooltip placement="top" content="加粗" :hide-after="0">
|
|
<el-tooltip placement="top" content="加粗" :hide-after="0">
|
|
|
<el-checkbox-button :value="hasFontWeight" @change="handleElementBlod()">
|
|
<el-checkbox-button :value="hasFontWeight" @change="handleElementBlod()">
|
|
|
- <IconTextBold />
|
|
|
|
|
|
|
+ <IconTextBold/>
|
|
|
</el-checkbox-button>
|
|
</el-checkbox-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="斜体" :hide-after="0">
|
|
<el-tooltip placement="top" content="斜体" :hide-after="0">
|
|
|
<el-checkbox-button v-model="hasFontStyle" @change="handleElementItalic()">
|
|
<el-checkbox-button v-model="hasFontStyle" @change="handleElementItalic()">
|
|
|
- <IconTextItalic />
|
|
|
|
|
|
|
+ <IconTextItalic/>
|
|
|
</el-checkbox-button>
|
|
</el-checkbox-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="下划线" :hide-after="0">
|
|
<el-tooltip placement="top" content="下划线" :hide-after="0">
|
|
|
<el-checkbox-button v-model="hasUnderline" @change="handleElementUnderline()">
|
|
<el-checkbox-button v-model="hasUnderline" @change="handleElementUnderline()">
|
|
|
- <IconTextUnderline />
|
|
|
|
|
|
|
+ <IconTextUnderline/>
|
|
|
</el-checkbox-button>
|
|
</el-checkbox-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="删除线" :hide-after="0">
|
|
<el-tooltip placement="top" content="删除线" :hide-after="0">
|
|
|
<el-checkbox-button v-model="hasLinethrough" @change="handleElementLinethrough()">
|
|
<el-checkbox-button v-model="hasLinethrough" @change="handleElementLinethrough()">
|
|
|
- <IconStrikethrough />
|
|
|
|
|
|
|
+ <IconStrikethrough/>
|
|
|
</el-checkbox-button>
|
|
</el-checkbox-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
</div>
|
|
</div>
|
|
@@ -104,22 +116,22 @@
|
|
|
<el-button-group class="full-group">
|
|
<el-button-group class="full-group">
|
|
|
<el-tooltip placement="top" content="横向" :hide-after="0">
|
|
<el-tooltip placement="top" content="横向" :hide-after="0">
|
|
|
<el-button @click="handleElementArrange(false)" :type="elementGrapheme ? 'primary': ''">
|
|
<el-button @click="handleElementArrange(false)" :type="elementGrapheme ? 'primary': ''">
|
|
|
- <IconTextRotationNone />
|
|
|
|
|
|
|
+ <IconTextRotationNone/>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="纵向" :hide-after="0">
|
|
<el-tooltip placement="top" content="纵向" :hide-after="0">
|
|
|
<el-button @click="handleElementArrange(true)" :type="!elementGrapheme ? 'primary': ''">
|
|
<el-button @click="handleElementArrange(true)" :type="!elementGrapheme ? 'primary': ''">
|
|
|
- <IconTextRotationDown />
|
|
|
|
|
|
|
+ <IconTextRotationDown/>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="减小缩进" :hide-after="0">
|
|
<el-tooltip placement="top" content="减小缩进" :hide-after="0">
|
|
|
<el-button @click="handleElementCharSpacing('-')">
|
|
<el-button @click="handleElementCharSpacing('-')">
|
|
|
- <IconIndentLeft />
|
|
|
|
|
|
|
+ <IconIndentLeft/>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="增大缩进" :hide-after="0">
|
|
<el-tooltip placement="top" content="增大缩进" :hide-after="0">
|
|
|
<el-button @click="handleElementCharSpacing('+')">
|
|
<el-button @click="handleElementCharSpacing('+')">
|
|
|
- <IconIndentRight />
|
|
|
|
|
|
|
+ <IconIndentRight/>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
</el-button-group>
|
|
</el-button-group>
|
|
@@ -130,22 +142,22 @@
|
|
|
<el-radio-group class="full-ratio" v-model="textAlign" @change="handleTextAlign">
|
|
<el-radio-group class="full-ratio" v-model="textAlign" @change="handleTextAlign">
|
|
|
<el-tooltip placement="top" content="左对齐" :hide-after="0">
|
|
<el-tooltip placement="top" content="左对齐" :hide-after="0">
|
|
|
<el-radio-button value="justify-left">
|
|
<el-radio-button value="justify-left">
|
|
|
- <IconAlignTextLeft />
|
|
|
|
|
|
|
+ <IconAlignTextLeft/>
|
|
|
</el-radio-button>
|
|
</el-radio-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="居中" :hide-after="0">
|
|
<el-tooltip placement="top" content="居中" :hide-after="0">
|
|
|
<el-radio-button value="justify-center">
|
|
<el-radio-button value="justify-center">
|
|
|
- <IconAlignTextCenter />
|
|
|
|
|
|
|
+ <IconAlignTextCenter/>
|
|
|
</el-radio-button>
|
|
</el-radio-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="右对齐" :hide-after="0">
|
|
<el-tooltip placement="top" content="右对齐" :hide-after="0">
|
|
|
<el-radio-button value="justify-right">
|
|
<el-radio-button value="justify-right">
|
|
|
- <IconAlignTextRight />
|
|
|
|
|
|
|
+ <IconAlignTextRight/>
|
|
|
</el-radio-button>
|
|
</el-radio-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="两边对齐" :hide-after="0">
|
|
<el-tooltip placement="top" content="两边对齐" :hide-after="0">
|
|
|
<el-radio-button value="justify">
|
|
<el-radio-button value="justify">
|
|
|
- <IconAlignTextBoth />
|
|
|
|
|
|
|
+ <IconAlignTextBoth/>
|
|
|
</el-radio-button>
|
|
</el-radio-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
</el-radio-group>
|
|
</el-radio-group>
|
|
@@ -156,14 +168,16 @@
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-tooltip placement="top" content="转曲" :hide-after="0">
|
|
<el-tooltip placement="top" content="转曲" :hide-after="0">
|
|
|
<el-button class="full-button" @click="handleElementCurve">
|
|
<el-button class="full-button" @click="handleElementCurve">
|
|
|
- <IconTextStyleOne />
|
|
|
|
|
|
|
+ <IconTextStyleOne/>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="12">
|
|
<el-col :span="12">
|
|
|
<el-tooltip placement="top" content="变形" :hide-after="0">
|
|
<el-tooltip placement="top" content="变形" :hide-after="0">
|
|
|
- <el-button class="full-button" :type="handleElement.type.toLowerCase() === ElementNames.ARCTEXT ? 'primary' : ''" @click="handleElementDeformation">
|
|
|
|
|
- <i class="handler-item iconfont icon-text-path" />
|
|
|
|
|
|
|
+ <el-button class="full-button"
|
|
|
|
|
+ :type="handleElement.type.toLowerCase() === ElementNames.ARCTEXT ? 'primary' : ''"
|
|
|
|
|
+ @click="handleElementDeformation">
|
|
|
|
|
+ <i class="handler-item iconfont icon-text-path"/>
|
|
|
</el-button>
|
|
</el-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
</el-col>
|
|
</el-col>
|
|
@@ -171,74 +185,80 @@
|
|
|
|
|
|
|
|
<el-row class="mt-10" v-show="handleElement.type.toLowerCase() === ElementNames.ARCTEXT">
|
|
<el-row class="mt-10" v-show="handleElement.type.toLowerCase() === ElementNames.ARCTEXT">
|
|
|
<el-col :span="4" class="flex-align">
|
|
<el-col :span="4" class="flex-align">
|
|
|
- <el-radio-group class="full-ratio" v-model="(handleElement as ArcText).showCurvature" @change="changeArcTextStatus">
|
|
|
|
|
- <el-tooltip placement="top" content="隐藏弧度" :hide-after="0" v-if="(handleElement as ArcText).showCurvature">
|
|
|
|
|
|
|
+ <el-radio-group class="full-ratio" v-model="(handleElement as ArcText).showCurvature"
|
|
|
|
|
+ @change="changeArcTextStatus">
|
|
|
|
|
+ <el-tooltip placement="top" content="隐藏弧度" :hide-after="0"
|
|
|
|
|
+ v-if="(handleElement as ArcText).showCurvature">
|
|
|
<el-radio-button :value="false">
|
|
<el-radio-button :value="false">
|
|
|
- <IconPreviewClose />
|
|
|
|
|
|
|
+ <IconPreviewClose/>
|
|
|
</el-radio-button>
|
|
</el-radio-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="显示弧度" :hide-after="0" v-else>
|
|
<el-tooltip placement="top" content="显示弧度" :hide-after="0" v-else>
|
|
|
<el-radio-button :value="true">
|
|
<el-radio-button :value="true">
|
|
|
- <IconPreviewOpen />
|
|
|
|
|
|
|
+ <IconPreviewOpen/>
|
|
|
</el-radio-button>
|
|
</el-radio-button>
|
|
|
</el-tooltip>
|
|
</el-tooltip>
|
|
|
</el-radio-group>
|
|
</el-radio-group>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="1"></el-col>
|
|
<el-col :span="1"></el-col>
|
|
|
<el-col :span="12" class="flex-align">
|
|
<el-col :span="12" class="flex-align">
|
|
|
- <el-slider :min="66" :max="1000" :step="1" v-model="(handleElement as ArcText).radius" @change="changeArcTextRadius" size="small"></el-slider>
|
|
|
|
|
|
|
+ <el-slider :min="66" :max="1000" :step="1" v-model="(handleElement as ArcText).radius"
|
|
|
|
|
+ @change="changeArcTextRadius" size="small"></el-slider>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
<el-col :span="1"></el-col>
|
|
<el-col :span="1"></el-col>
|
|
|
<el-col :span="6" class="flex-align">
|
|
<el-col :span="6" class="flex-align">
|
|
|
- <el-input :min="1" :max="10" v-model="(handleElement as ArcText).radius" controls-position="right" size="default"/>
|
|
|
|
|
|
|
+ <el-input :min="1" :max="10" v-model="(handleElement as ArcText).radius" controls-position="right"
|
|
|
|
|
+ size="default"/>
|
|
|
</el-col>
|
|
</el-col>
|
|
|
</el-row>
|
|
</el-row>
|
|
|
|
|
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
- <ElementFill />
|
|
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
|
|
+ <ElementFill/>
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
|
|
|
|
|
<div class="row">
|
|
<div class="row">
|
|
|
<div style="flex: 2;">行距:</div>
|
|
<div style="flex: 2;">行距:</div>
|
|
|
- <el-select style="flex: 3" suffix-icon="IconRowHeight" v-model="handleElement.lineHeight" @change="changeLineHeight">
|
|
|
|
|
|
|
+ <el-select style="flex: 3" suffix-icon="IconRowHeight" v-model="handleElement.lineHeight"
|
|
|
|
|
+ @change="changeLineHeight">
|
|
|
<el-option v-for="item in LineHeightLibs" :key="item" :value="item" :label="item"></el-option>
|
|
<el-option v-for="item in LineHeightLibs" :key="item" :value="item" :label="item"></el-option>
|
|
|
</el-select>
|
|
</el-select>
|
|
|
<div style="flex: 1;"></div>
|
|
<div style="flex: 1;"></div>
|
|
|
<div style="flex: 2;">字距:</div>
|
|
<div style="flex: 2;">字距:</div>
|
|
|
- <el-select style="flex: 3" suffix-icon="IconFullwidth" v-model="handleElement.charSpacing" @change="changeCharSpacing">
|
|
|
|
|
|
|
+ <el-select style="flex: 3" suffix-icon="IconFullwidth" v-model="handleElement.charSpacing"
|
|
|
|
|
+ @change="changeCharSpacing">
|
|
|
<el-option v-for="item in CharSpaceLibs" :key="item" :value="item" :label="item"></el-option>
|
|
<el-option v-for="item in CharSpaceLibs" :key="item" :value="item" :label="item"></el-option>
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
- <ElementEffects />
|
|
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
- <ElementStroke :hasStroke="hasStroke" />
|
|
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
- <ElementShadow :hasShadow="hasShadow" />
|
|
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
- <ElementPatterns :hasPatterns="hasPatterns" />
|
|
|
|
|
- <el-divider style="margin: 12px 0" />
|
|
|
|
|
- <ElementOpacity />
|
|
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
|
|
+ <ElementEffects/>
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
|
|
+ <ElementStroke :hasStroke="hasStroke"/>
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
|
|
+ <ElementShadow :hasShadow="hasShadow"/>
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
|
|
+ <ElementPatterns :hasPatterns="hasPatterns"/>
|
|
|
|
|
+ <el-divider style="margin: 12px 0"/>
|
|
|
|
|
+ <ElementOpacity/>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
|
<script lang="ts" setup>
|
|
|
-import { computed, ref, onMounted } from 'vue'
|
|
|
|
|
-import { useMainStore, useTemplatesStore } from '@/store'
|
|
|
|
|
-import { storeToRefs } from 'pinia'
|
|
|
|
|
-import { ElMessage } from 'element-plus'
|
|
|
|
|
-import { FabricObject, IText, Textbox } from 'fabric'
|
|
|
|
|
-import { FontSizeLibs, LineHeightLibs, CharSpaceLibs } from '@/configs/texts'
|
|
|
|
|
-import { WEB_FONTS } from '@/configs/fonts'
|
|
|
|
|
-import { propertiesToInclude } from '@/configs/canvas'
|
|
|
|
|
-import { TextboxElement } from '@/types/canvas'
|
|
|
|
|
-import { ElementNames, FontGroupOption } from '@/types/elements'
|
|
|
|
|
-import { loadFont } from '@/utils/fonts'
|
|
|
|
|
-import { nanoid } from 'nanoid'
|
|
|
|
|
-import { ArcText } from '@/extension/object/ArcText'
|
|
|
|
|
-import { CurvedText } from '@/extension/object/CurvedText'
|
|
|
|
|
-import { VerticalText } from '@/extension/object/VerticalText'
|
|
|
|
|
|
|
+import {computed, ref, onMounted} from 'vue'
|
|
|
|
|
+import {useMainStore, useTemplatesStore} from '@/store'
|
|
|
|
|
+import {storeToRefs} from 'pinia'
|
|
|
|
|
+import {ElMessage} from 'element-plus'
|
|
|
|
|
+import {FabricObject, IText, Textbox} from 'fabric'
|
|
|
|
|
+import {FontSizeLibs, LineHeightLibs, CharSpaceLibs} from '@/configs/texts'
|
|
|
|
|
+import {WEB_FONTS} from '@/configs/fonts'
|
|
|
|
|
+import {propertiesToInclude} from '@/configs/canvas'
|
|
|
|
|
+import {TextboxElement} from '@/types/canvas'
|
|
|
|
|
+import {ElementNames, FontGroupOption} from '@/types/elements'
|
|
|
|
|
+import {loadFont} from '@/utils/fonts'
|
|
|
|
|
+import {nanoid} from 'nanoid'
|
|
|
|
|
+import {ArcText} from '@/extension/object/ArcText'
|
|
|
|
|
+import {CurvedText} from '@/extension/object/CurvedText'
|
|
|
|
|
+import {VerticalText} from '@/extension/object/VerticalText'
|
|
|
import opentype from "opentype.js"
|
|
import opentype from "opentype.js"
|
|
|
import ElementPosition from '../Components/ElementPosition.vue'
|
|
import ElementPosition from '../Components/ElementPosition.vue'
|
|
|
import ElementStroke from '../Components/ElementStroke.vue'
|
|
import ElementStroke from '../Components/ElementStroke.vue'
|
|
@@ -251,12 +271,11 @@ import useHandleCreate from "@/hooks/useHandleCreate"
|
|
|
import useCanvas from '@/views/Canvas/useCanvas'
|
|
import useCanvas from '@/views/Canvas/useCanvas'
|
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
const mainStore = useMainStore()
|
|
const mainStore = useMainStore()
|
|
|
const templatesStore = useTemplatesStore()
|
|
const templatesStore = useTemplatesStore()
|
|
|
-const { canvasObject, systemFonts, onlineFonts } = storeToRefs(mainStore)
|
|
|
|
|
-const { createPathElement } = useHandleCreate()
|
|
|
|
|
-const [ canvas ] = useCanvas()
|
|
|
|
|
|
|
+const {canvasObject, systemFonts, onlineFonts} = storeToRefs(mainStore)
|
|
|
|
|
+const {createPathElement} = useHandleCreate()
|
|
|
|
|
+const [canvas] = useCanvas()
|
|
|
const handleElement = computed(() => canvasObject.value as Textbox | ArcText)
|
|
const handleElement = computed(() => canvasObject.value as Textbox | ArcText)
|
|
|
const elementGrapheme = computed(() => handleElement.value.type.toLowerCase() !== ElementNames.VERTICALTEXT)
|
|
const elementGrapheme = computed(() => handleElement.value.type.toLowerCase() !== ElementNames.VERTICALTEXT)
|
|
|
const elementBackgrounColor = computed(() => {
|
|
const elementBackgrounColor = computed(() => {
|
|
@@ -277,10 +296,12 @@ const hasPatterns = computed(() => (handleElement.value as TextboxElement).fillT
|
|
|
const elementFontFamily = ref<string>(hasFontFamily.value)
|
|
const elementFontFamily = ref<string>(hasFontFamily.value)
|
|
|
const fontOptionGroups = ref<FontGroupOption[]>([
|
|
const fontOptionGroups = ref<FontGroupOption[]>([
|
|
|
{
|
|
{
|
|
|
|
|
+ type: 0,
|
|
|
label: '系统字体',
|
|
label: '系统字体',
|
|
|
options: systemFonts.value
|
|
options: systemFonts.value
|
|
|
},
|
|
},
|
|
|
{
|
|
{
|
|
|
|
|
+ type: 1,
|
|
|
label: '在线字体',
|
|
label: '在线字体',
|
|
|
options: onlineFonts.value
|
|
options: onlineFonts.value
|
|
|
}
|
|
}
|
|
@@ -290,8 +311,7 @@ const fontOptionGroups = ref<FontGroupOption[]>([
|
|
|
const handleElementFontFamily = (fontFamily: string) => {
|
|
const handleElementFontFamily = (fontFamily: string) => {
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({fontFamily})
|
|
handleElement.value.setSelectionStyles({fontFamily})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {fontFamily})
|
|
templatesStore.modifedElement(handleElement.value, {fontFamily})
|
|
|
}
|
|
}
|
|
|
canvas.renderAll()
|
|
canvas.renderAll()
|
|
@@ -311,8 +331,7 @@ const handleElementFontSize = (fontSize: string) => {
|
|
|
if (!fontSize) return
|
|
if (!fontSize) return
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({fontSize})
|
|
handleElement.value.setSelectionStyles({fontSize})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {fontSize})
|
|
templatesStore.modifedElement(handleElement.value, {fontSize})
|
|
|
}
|
|
}
|
|
|
canvas.renderAll()
|
|
canvas.renderAll()
|
|
@@ -320,25 +339,23 @@ const handleElementFontSize = (fontSize: string) => {
|
|
|
|
|
|
|
|
// 修改字体颜色
|
|
// 修改字体颜色
|
|
|
const updateFontColor = (fill: string) => {
|
|
const updateFontColor = (fill: string) => {
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({fill})
|
|
handleElement.value.setSelectionStyles({fill})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {fill, color: fill})
|
|
templatesStore.modifedElement(handleElement.value, {fill, color: fill})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 修改背景颜色
|
|
// 修改背景颜色
|
|
|
const updateBackgroundColor = (backgroundColor: string) => {
|
|
const updateBackgroundColor = (backgroundColor: string) => {
|
|
|
- let changeData: Record<string, any> = { backgroundColor }
|
|
|
|
|
|
|
+ let changeData: Record<string, any> = {backgroundColor}
|
|
|
if (handleElement.value.type.toLowerCase() === ElementNames.ARCTEXT) {
|
|
if (handleElement.value.type.toLowerCase() === ElementNames.ARCTEXT) {
|
|
|
- changeData = { 'textBackgroundColor': backgroundColor }
|
|
|
|
|
|
|
+ changeData = {'textBackgroundColor': backgroundColor}
|
|
|
}
|
|
}
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles(changeData)
|
|
handleElement.value.setSelectionStyles(changeData)
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, changeData)
|
|
templatesStore.modifedElement(handleElement.value, changeData)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -349,8 +366,7 @@ const handleElementFontsize = (mode: string) => {
|
|
|
const fontSize = mode === '+' ? handleElement.value.fontSize + 1 : handleElement.value.fontSize - 1
|
|
const fontSize = mode === '+' ? handleElement.value.fontSize + 1 : handleElement.value.fontSize - 1
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({fontSize})
|
|
handleElement.value.setSelectionStyles({fontSize})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {fontSize})
|
|
templatesStore.modifedElement(handleElement.value, {fontSize})
|
|
|
}
|
|
}
|
|
|
canvas.renderAll()
|
|
canvas.renderAll()
|
|
@@ -363,12 +379,10 @@ const handleElementBlod = () => {
|
|
|
const blodState = handleElement.value.getSelectionStyles().find(item => item.fontWeight !== fontBold)
|
|
const blodState = handleElement.value.getSelectionStyles().find(item => item.fontWeight !== fontBold)
|
|
|
if (!blodState || (JSON.stringify(blodState) === '{}' && handleElement.value.fontWeight === fontBold)) {
|
|
if (!blodState || (JSON.stringify(blodState) === '{}' && handleElement.value.fontWeight === fontBold)) {
|
|
|
handleElement.value.setSelectionStyles({'fontWeight': fontNormal})
|
|
handleElement.value.setSelectionStyles({'fontWeight': fontNormal})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
handleElement.value.setSelectionStyles({'fontWeight': fontBold})
|
|
handleElement.value.setSelectionStyles({'fontWeight': fontBold})
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
const elementStyle = handleElement.value.styles
|
|
const elementStyle = handleElement.value.styles
|
|
|
if (handleElement.value.fontWeight === fontBold) {
|
|
if (handleElement.value.fontWeight === fontBold) {
|
|
|
templatesStore.modifedElement(handleElement.value, {fontWeight: fontNormal})
|
|
templatesStore.modifedElement(handleElement.value, {fontWeight: fontNormal})
|
|
@@ -377,8 +391,7 @@ const handleElementBlod = () => {
|
|
|
(elementStyle[i][j] as TextboxElement).set({fontWeight: fontNormal})
|
|
(elementStyle[i][j] as TextboxElement).set({fontWeight: fontNormal})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {fontWeight: fontBold})
|
|
templatesStore.modifedElement(handleElement.value, {fontWeight: fontBold})
|
|
|
for (let i in elementStyle) {
|
|
for (let i in elementStyle) {
|
|
|
for (let j in elementStyle[i]) {
|
|
for (let j in elementStyle[i]) {
|
|
@@ -392,23 +405,21 @@ const handleElementBlod = () => {
|
|
|
|
|
|
|
|
// 修改斜体
|
|
// 修改斜体
|
|
|
const handleElementItalic = () => {
|
|
const handleElementItalic = () => {
|
|
|
- const fontStyle = handleElement.value.fontStyle === 'italic' ? 'normal': 'italic'
|
|
|
|
|
|
|
+ const fontStyle = handleElement.value.fontStyle === 'italic' ? 'normal' : 'italic'
|
|
|
|
|
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({fontStyle})
|
|
handleElement.value.setSelectionStyles({fontStyle})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {fontStyle})
|
|
templatesStore.modifedElement(handleElement.value, {fontStyle})
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 修改删除线
|
|
// 修改删除线
|
|
|
const handleElementLinethrough = () => {
|
|
const handleElementLinethrough = () => {
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({linethrough: !handleElement.value.linethrough})
|
|
handleElement.value.setSelectionStyles({linethrough: !handleElement.value.linethrough})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {linethrough: !handleElement.value.linethrough})
|
|
templatesStore.modifedElement(handleElement.value, {linethrough: !handleElement.value.linethrough})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -417,8 +428,7 @@ const handleElementLinethrough = () => {
|
|
|
const handleElementUnderline = () => {
|
|
const handleElementUnderline = () => {
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({underline: !handleElement.value.underline})
|
|
handleElement.value.setSelectionStyles({underline: !handleElement.value.underline})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {underline: !handleElement.value.underline})
|
|
templatesStore.modifedElement(handleElement.value, {underline: !handleElement.value.underline})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -427,8 +437,7 @@ const handleElementUnderline = () => {
|
|
|
const handleTextAlign = (textAlign: string) => {
|
|
const handleTextAlign = (textAlign: string) => {
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({textAlign})
|
|
handleElement.value.setSelectionStyles({textAlign})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {textAlign})
|
|
templatesStore.modifedElement(handleElement.value, {textAlign})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -437,26 +446,24 @@ const handleTextAlign = (textAlign: string) => {
|
|
|
const handleElementCharSpacing = (mode: '+' | '-') => {
|
|
const handleElementCharSpacing = (mode: '+' | '-') => {
|
|
|
const handleCharSpacing = handleElement.value.charSpacing
|
|
const handleCharSpacing = handleElement.value.charSpacing
|
|
|
const charSpacing = mode === '+' ? handleCharSpacing + 10 : handleCharSpacing - 10
|
|
const charSpacing = mode === '+' ? handleCharSpacing + 10 : handleCharSpacing - 10
|
|
|
- templatesStore.modifedElement(handleElement.value, { charSpacing })
|
|
|
|
|
|
|
+ templatesStore.modifedElement(handleElement.value, {charSpacing})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const changeLineHeight = (lineHeight: number) => {
|
|
const changeLineHeight = (lineHeight: number) => {
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({lineHeight})
|
|
handleElement.value.setSelectionStyles({lineHeight})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- templatesStore.modifedElement(handleElement.value, { lineHeight })
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ templatesStore.modifedElement(handleElement.value, {lineHeight})
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const changeCharSpacing = (charSpacing: number) => {
|
|
const changeCharSpacing = (charSpacing: number) => {
|
|
|
if (handleElement.value.isEditing) {
|
|
if (handleElement.value.isEditing) {
|
|
|
handleElement.value.setSelectionStyles({charSpacing})
|
|
handleElement.value.setSelectionStyles({charSpacing})
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
|
|
+ } else {
|
|
|
templatesStore.modifedElement(handleElement.value, {charSpacing})
|
|
templatesStore.modifedElement(handleElement.value, {charSpacing})
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
canvas.renderAll()
|
|
canvas.renderAll()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -519,12 +526,12 @@ const handleElementDeformation = () => {
|
|
|
|
|
|
|
|
const changeArcTextRadius = (val: number) => {
|
|
const changeArcTextRadius = (val: number) => {
|
|
|
(handleElement.value as ArcText).setRadius(val)
|
|
(handleElement.value as ArcText).setRadius(val)
|
|
|
- templatesStore.modifedElement(handleElement.value, { radius: val })
|
|
|
|
|
|
|
+ templatesStore.modifedElement(handleElement.value, {radius: val})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const changeArcTextStatus = (showCurvature: boolean) => {
|
|
const changeArcTextStatus = (showCurvature: boolean) => {
|
|
|
(handleElement.value as ArcText).set({showCurvature})
|
|
(handleElement.value as ArcText).set({showCurvature})
|
|
|
- templatesStore.modifedElement(handleElement.value, { showCurvature })
|
|
|
|
|
|
|
+ templatesStore.modifedElement(handleElement.value, {showCurvature})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
</script>
|
|
</script>
|
|
@@ -533,17 +540,20 @@ const changeArcTextStatus = (showCurvature: boolean) => {
|
|
|
.text-style-panel {
|
|
.text-style-panel {
|
|
|
user-select: none;
|
|
user-select: none;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.row {
|
|
.row {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
margin-bottom: 10px;
|
|
margin-bottom: 10px;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.preset-style {
|
|
.preset-style {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
flex-wrap: wrap;
|
|
|
margin-bottom: 10px;
|
|
margin-bottom: 10px;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.preset-style-item {
|
|
.preset-style-item {
|
|
|
width: 50%;
|
|
width: 50%;
|
|
|
height: 50px;
|
|
height: 50px;
|
|
@@ -565,26 +575,33 @@ const changeArcTextStatus = (showCurvature: boolean) => {
|
|
|
&:nth-child(2n) {
|
|
&:nth-child(2n) {
|
|
|
margin-left: -1px;
|
|
margin-left: -1px;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
&:nth-child(n+3) {
|
|
&:nth-child(n+3) {
|
|
|
margin-top: -1px;
|
|
margin-top: -1px;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.font-size-btn {
|
|
.font-size-btn {
|
|
|
padding: 0;
|
|
padding: 0;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.link-popover {
|
|
.link-popover {
|
|
|
width: 240px;
|
|
width: 240px;
|
|
|
|
|
+
|
|
|
.btns {
|
|
.btns {
|
|
|
margin-top: 10px;
|
|
margin-top: 10px;
|
|
|
text-align: right;
|
|
text-align: right;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.mt-10 {
|
|
.mt-10 {
|
|
|
margin-top: 10px;
|
|
margin-top: 10px;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.full-group {
|
|
.full-group {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
|
|
+
|
|
|
.el-button {
|
|
.el-button {
|
|
|
width: 50%;
|
|
width: 50%;
|
|
|
}
|
|
}
|
|
@@ -595,32 +612,39 @@ const changeArcTextStatus = (showCurvature: boolean) => {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
border-radius: 0;
|
|
border-radius: 0;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.font-color {
|
|
.font-color {
|
|
|
border-top-left-radius: 4px;
|
|
border-top-left-radius: 4px;
|
|
|
border-bottom-left-radius: 4px;
|
|
border-bottom-left-radius: 4px;
|
|
|
border-right: 0;
|
|
border-right: 0;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.high-light {
|
|
.high-light {
|
|
|
border-right: 0;
|
|
border-right: 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.font-size {
|
|
.font-size {
|
|
|
border-top-left-radius: 0;
|
|
border-top-left-radius: 0;
|
|
|
border-bottom-left-radius: 0;
|
|
border-bottom-left-radius: 0;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.full-ratio {
|
|
.full-ratio {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
|
|
+
|
|
|
.el-radio-button {
|
|
.el-radio-button {
|
|
|
position: relative;
|
|
position: relative;
|
|
|
display: inline-flex;
|
|
display: inline-flex;
|
|
|
outline: 0;
|
|
outline: 0;
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.el-radio-button__inner {
|
|
.el-radio-button__inner {
|
|
|
width: 100%
|
|
width: 100%
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.flex-align {
|
|
.flex-align {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
@@ -630,8 +654,10 @@ const changeArcTextStatus = (showCurvature: boolean) => {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
.full-button {
|
|
.full-button {
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
|
|
+
|
|
|
.iconfont {
|
|
.iconfont {
|
|
|
font-size: 32px;
|
|
font-size: 32px;
|
|
|
}
|
|
}
|
|
@@ -650,6 +676,7 @@ const changeArcTextStatus = (showCurvature: boolean) => {
|
|
|
outline: 0;
|
|
outline: 0;
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
:deep(.full-checkbox .el-checkbox-button) {
|
|
:deep(.full-checkbox .el-checkbox-button) {
|
|
|
position: relative;
|
|
position: relative;
|
|
|
display: inline-flex;
|
|
display: inline-flex;
|