327 lines
8.2 KiB
Vue
327 lines
8.2 KiB
Vue
<template>
|
|
<div class="header-tools">
|
|
<template v-for="(v, i) in tools" :key="i">
|
|
<span class="line" v-if="v.type === 'line'"></span>
|
|
<div v-else class="item">
|
|
<span
|
|
class="icon"
|
|
@click="onClickTool(v)"
|
|
:class="{
|
|
active: v.name === tool || v.tools?.includes(tool),
|
|
disabled: v.disabled
|
|
}"
|
|
>
|
|
<svg-icon :name="v.icon" :size="v.iconSize" />
|
|
</span>
|
|
<span class="more" v-if="v.child" @click="onClickMore(v)">
|
|
<svg-icon name="dc-down_arrow2" size="7" />
|
|
</span>
|
|
<div v-if="v.child" class="child" v-show="v.showChild">
|
|
<div v-for="(v_, i_) in v.child" :key="i_" @click="onClickTool(v_, v)">
|
|
<span v-show="tool === v_.name" class="dui">
|
|
<svg-icon name="dc-dui" size="9" />
|
|
</span>
|
|
<span class="icon"><svg-icon :name="v_.icon" :size="v_.iconSize" /></span>
|
|
<span class="label">{{ v_.label }}</span>
|
|
<span class="tip">{{ v_.tip }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<button class="export" @click="emit('export')">
|
|
<span class="icon"><svg-icon name="export" size="12" /></span>
|
|
<span class="text">{{ $t('DepthCanvas.export') }}</span>
|
|
</button>
|
|
<!-- <button class="export" @click="emit('export-local')">
|
|
<span class="text">保存本地</span>
|
|
</button>
|
|
<button class="export" @click="emit('import-local')">
|
|
<span class="text">本地导入</span>
|
|
</button> -->
|
|
<button class="workbench" @click="onWorkbench">
|
|
<span class="icon"><svg-icon name="dc-workbench" size="20" /></span>
|
|
<span class="text">{{ $t('DepthCanvas.save') }}</span>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, inject, computed } from 'vue'
|
|
import { exportCanvasToImage } from '../tools/exportMethod'
|
|
import { OperationType, BlendMode } from '../tools/layerHelper'
|
|
import { useI18n } from 'vue-i18n'
|
|
const { t } = useI18n()
|
|
const props = defineProps({
|
|
zoom: { default: 1, type: Number },
|
|
step: { default: 0.1, type: Number }
|
|
})
|
|
const emit = defineEmits(['export', 'workbench'])
|
|
const importLocalImage = inject('importLocalImage') as (isRecord?: boolean) => void
|
|
const stateManager = inject('stateManager') as any
|
|
const toolManager = inject('toolManager') as any
|
|
const objectManager = inject('objectManager') as any
|
|
const canvasManager = inject('canvasManager') as any
|
|
const layerManager = inject('layerManager') as any
|
|
const tool = computed(() => toolManager.currentTool.value)
|
|
const historyIndex = computed(() => stateManager.historyIndex.value)
|
|
const historyList = computed(() => stateManager.historyList.value)
|
|
const isUndo = computed(() => !historyList.value[historyIndex.value - 1])
|
|
const isRedo = computed(() => !historyList.value[historyIndex.value + 1])
|
|
const activeLayerId = computed(() => layerManager.activeID.value)
|
|
const tools = ref([
|
|
{ name: OperationType.SELECT, icon: 'dc-select', iconSize: 16 },
|
|
{ name: OperationType.PAN, icon: 'dc-move', iconSize: 18 },
|
|
{ name: OperationType.DRAW, icon: 'dc-brush', iconSize: 18 },
|
|
{ name: OperationType.ERASER, icon: 'dc-eraser', iconSize: 18 },
|
|
{ icon: 'dc-image', iconSize: 17, on: () => onImageClick() },
|
|
{
|
|
name: OperationType.AISELECT_ADD,
|
|
icon: 'dc-selectbox',
|
|
iconSize: 16,
|
|
tools: stateManager.aiSelectboxToolManager.tools
|
|
},
|
|
{
|
|
name: OperationType.RECTANGLE,
|
|
icon: 'dc-rectangle',
|
|
iconSize: 16,
|
|
showChild: false,
|
|
child: [
|
|
{
|
|
name: OperationType.RECTANGLE,
|
|
label: t('DepthCanvas.rectangle'),
|
|
icon: 'dc-rectangle',
|
|
iconSize: 13
|
|
},
|
|
{
|
|
name: OperationType.LINE,
|
|
label: t('DepthCanvas.line'),
|
|
icon: 'dc-line',
|
|
iconSize: 10
|
|
},
|
|
{
|
|
name: OperationType.ARROW,
|
|
label: t('DepthCanvas.arrow'),
|
|
icon: 'dc-arrow',
|
|
iconSize: 11
|
|
},
|
|
{
|
|
name: OperationType.ELLIPSE,
|
|
label: t('DepthCanvas.ellipse'),
|
|
icon: 'dc-ellipse',
|
|
iconSize: 15
|
|
},
|
|
{
|
|
name: OperationType.TRIANGLE,
|
|
label: t('DepthCanvas.triangle'),
|
|
icon: 'dc-triangle',
|
|
iconSize: 14
|
|
},
|
|
{
|
|
name: OperationType.STAR,
|
|
label: t('DepthCanvas.star'),
|
|
icon: 'dc-star',
|
|
iconSize: 15
|
|
}
|
|
]
|
|
},
|
|
|
|
{ type: 'line' },
|
|
{
|
|
icon: 'dc-undo',
|
|
iconSize: 18,
|
|
disabled: isUndo,
|
|
on: () => stateManager.undoState()
|
|
},
|
|
{
|
|
icon: 'dc-redo',
|
|
iconSize: 18,
|
|
disabled: isRedo,
|
|
on: () => stateManager.redoState()
|
|
},
|
|
{
|
|
name: 'copy',
|
|
icon: 'dc-copy',
|
|
iconSize: 16,
|
|
disabled: computed(() => !activeLayerId.value),
|
|
on: () => onCopyActiveLayer()
|
|
},
|
|
{
|
|
name: 'delete',
|
|
icon: 'dc-delete',
|
|
iconSize: 18,
|
|
disabled: computed(() => !activeLayerId.value),
|
|
on: () => onDeleteActiveLayer()
|
|
}
|
|
])
|
|
const onClickTool = (v: any, parent?: any) => {
|
|
if (v.disabled?.value) return
|
|
if (parent) {
|
|
parent.name = v.name
|
|
parent.icon = v.icon
|
|
parent.iconSize = v.iconSize * 1.23
|
|
}
|
|
tools.value.forEach((v) => v.hasOwnProperty('showChild') && (v.showChild = false))
|
|
v.on ? v.on() : toolManager.setTool(v.name)
|
|
}
|
|
const onClickMore = (v: any) => {
|
|
tools.value.forEach((item) => {
|
|
if (item.hasOwnProperty('showChild') && item.name !== v.name) item.showChild = false
|
|
})
|
|
v.showChild = !v.showChild
|
|
}
|
|
const onImageClick = async () => {
|
|
const layer = await importLocalImage(false)
|
|
const id = layer?.info?.id
|
|
objectManager.setBlendMode(id, BlendMode.MULTIPLY)
|
|
objectManager.setFillRepeat(id)
|
|
}
|
|
const onCopyActiveLayer = () => {
|
|
if (!activeLayerId.value) return
|
|
layerManager.copyLayerById(activeLayerId.value)
|
|
}
|
|
const onDeleteActiveLayer = () => {
|
|
if (!activeLayerId.value) return
|
|
layerManager.deleteLayerById(activeLayerId.value)
|
|
}
|
|
const onWorkbench = () => {
|
|
emit('workbench')
|
|
}
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.header-tools {
|
|
position: absolute;
|
|
top: 2.2rem;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
height: 5rem;
|
|
padding: 0.7rem 1.8rem;
|
|
border: 0.2rem solid #ebebeb;
|
|
background: #ffffff;
|
|
border-radius: 0.6rem;
|
|
box-shadow: 0 1.66rem 2.33rem 0 rgba(0, 0, 0, 0.05);
|
|
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
user-select: none;
|
|
gap: 1rem;
|
|
> .line {
|
|
width: 0;
|
|
height: 100%;
|
|
border-left: 0.2rem solid #d9d9d9;
|
|
border-radius: 0.2rem;
|
|
margin: 0 0.6rem;
|
|
}
|
|
> .item {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
> span {
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
--svg-icon-color: #000;
|
|
border-radius: 0.4rem;
|
|
height: 3rem;
|
|
&:not(.disabled).active,
|
|
&:not(.disabled):hover {
|
|
background-color: #ebebeb;
|
|
}
|
|
&.disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
> .icon {
|
|
width: 3rem;
|
|
}
|
|
> .more {
|
|
width: 1.1rem;
|
|
}
|
|
> .child {
|
|
cursor: pointer;
|
|
position: absolute;
|
|
min-width: 21rem;
|
|
top: calc(100% + 2rem);
|
|
left: 0;
|
|
padding: 0.6rem 0;
|
|
border: 0.1remx solid #d9d9d9;
|
|
background-color: #fff;
|
|
border-radius: 1.2rem;
|
|
box-shadow: 0 0.4rem 0.4rem 0 rgba(0, 0, 0, 0.25);
|
|
> div {
|
|
height: 3.2rem;
|
|
display: flex;
|
|
align-items: center;
|
|
// justify-content: center;
|
|
gap: 0.8rem;
|
|
position: relative;
|
|
padding: 0 1.6rem;
|
|
> .dui {
|
|
position: absolute;
|
|
left: 1.5rem;
|
|
transform: translateX(-50%);
|
|
}
|
|
> .icon {
|
|
width: 2rem;
|
|
height: 2rem;
|
|
margin-left: 0.8rem;
|
|
}
|
|
> .label {
|
|
flex: 1;
|
|
font-size: 1.4rem;
|
|
color: #000;
|
|
}
|
|
> .tip {
|
|
font-size: 1.3rem;
|
|
color: rgba(13, 13, 13, 0.65);
|
|
}
|
|
&:not(.disabled).active,
|
|
&:not(.disabled):hover {
|
|
background-color: #ebebeb;
|
|
}
|
|
&.disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
> button {
|
|
cursor: pointer;
|
|
border: none;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.8rem;
|
|
&:active {
|
|
opacity: 0.8;
|
|
}
|
|
}
|
|
> .export {
|
|
width: 10rem;
|
|
height: 3rem;
|
|
background-color: #0d0d0d;
|
|
color: #fff;
|
|
font-size: 1.2rem;
|
|
border-radius: 0.4rem;
|
|
}
|
|
> .workbench {
|
|
position: absolute;
|
|
top: 0;
|
|
right: -2.4rem;
|
|
transform: translateX(100%);
|
|
height: 100%;
|
|
padding: 0 2.4rem;
|
|
border: 0.2rem solid #ebebeb;
|
|
background: #ffffff;
|
|
border-radius: 0.6rem;
|
|
box-shadow: 0 1.66rem 2.33rem 0 rgba(0, 0, 0, 0.05);
|
|
font-size: 1.7rem;
|
|
}
|
|
}
|
|
</style>
|