Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/FiDA_Front
This commit is contained in:
@@ -79,3 +79,20 @@ body,
|
|||||||
--el-color-primary-light-9: #fff2ec;
|
--el-color-primary-light-9: #fff2ec;
|
||||||
--el-color-primary-dark-2: #cc6241;
|
--el-color-primary-dark-2: #cc6241;
|
||||||
}
|
}
|
||||||
|
.el-select,
|
||||||
|
.el-popper {
|
||||||
|
--el-color-primary: #6c6c6c;
|
||||||
|
/* 主灰色 */
|
||||||
|
--el-color-primary-light-3: #8a8a8a;
|
||||||
|
/* 较浅的灰色(混合20%白) */
|
||||||
|
--el-color-primary-light-5: #a8a8a8;
|
||||||
|
/* 更浅的灰色(混合33%白) */
|
||||||
|
--el-color-primary-light-7: #c6c6c6;
|
||||||
|
/* 浅灰色(混合47%白) */
|
||||||
|
--el-color-primary-light-8: #d4d4d4;
|
||||||
|
/* 很浅的灰色(混合53%白) */
|
||||||
|
--el-color-primary-light-9: #e3e3e3;
|
||||||
|
/* 极浅的灰色(混合60%白) */
|
||||||
|
--el-color-primary-dark-2: #565656;
|
||||||
|
/* 深灰色(加深20%) */
|
||||||
|
}
|
||||||
|
|||||||
@@ -96,3 +96,12 @@ body,
|
|||||||
--el-color-primary-light-9: #fff2ec; // 极浅的橙红(混合60%白)
|
--el-color-primary-light-9: #fff2ec; // 极浅的橙红(混合60%白)
|
||||||
--el-color-primary-dark-2: #cc6241; // 深橙红(加深20%)
|
--el-color-primary-dark-2: #cc6241; // 深橙红(加深20%)
|
||||||
}
|
}
|
||||||
|
.el-select, .el-popper{
|
||||||
|
--el-color-primary: #6c6c6c; /* 主灰色 */
|
||||||
|
--el-color-primary-light-3: #8a8a8a; /* 较浅的灰色(混合20%白) */
|
||||||
|
--el-color-primary-light-5: #a8a8a8; /* 更浅的灰色(混合33%白) */
|
||||||
|
--el-color-primary-light-7: #c6c6c6; /* 浅灰色(混合47%白) */
|
||||||
|
--el-color-primary-light-8: #d4d4d4; /* 很浅的灰色(混合53%白) */
|
||||||
|
--el-color-primary-light-9: #e3e3e3; /* 极浅的灰色(混合60%白) */
|
||||||
|
--el-color-primary-dark-2: #565656; /* 深灰色(加深20%) */
|
||||||
|
}
|
||||||
|
|||||||
9
src/assets/icons/dc/angle.svg
Normal file
9
src/assets/icons/dc/angle.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<rect width="8.0041" height="8.0041" fill="url(#pattern0_2958_107309)"/>
|
||||||
|
<defs>
|
||||||
|
<pattern id="pattern0_2958_107309" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||||
|
<use xlink:href="#image0_2958_107309" transform="scale(0.0078125)"/>
|
||||||
|
</pattern>
|
||||||
|
<image id="image0_2958_107309" width="128" height="128" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAA3NCSVQICAjb4U/gAAAACXBIWXMAAAN2AAADdgF91YLMAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAThQTFRF////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAR/EwCQAAAGd0Uk5TAAECBAUGBwoLDA8QEhUXGRocIiUnLC03PEBCRkdJS0xOVFZXWV1hYmdobnF1enyAgYKDhoeLjY+QkpSVmp6go6anr7S1uLq7wcTGx8jKy8zN0NPV19zg5+rr7vDx8vP09vf6+/z9/seyqosAAAGbSURBVHja7dhVUwNBEATgJri7uwR3lwDBggZ3OZz5//8Aqd17DpLqKqr7KbszV9+83GYTQFEURVH+eRpiiZkqHh+Zs488dtD8RfvKTSnXN+sh+zZG9q2T7J/lcv2gluzXyZcvX758+fLly5cvX758+fLly5cvX758+fLl/y/fJsm+PdZwfbPTPK5vtkT2zaJk34Iqih/Ewo9HOZz3fz1cLHDOn+KLcFnP8IHGN7/epvjAVLjTRPGRfeC3khQfqLz3m20UH5gIX8UMio+iW7/fTvGBEV84iVB8FFz7UhfFB4Z8bYPjI//KFZ8KKT4wmNav5RTun0XPrr7K8YFN1/CQx/HRl7ajIMX7f8mr64lzfGDLNd3lcHz0+7YWjo9yfzEZ5fjAoWtcIfnwzYckPzwMA5KPVt9cxvFR8bfX8+///xB5cO29HB84cv3TJB9x98Da3/q2PZti9t0Dl7M/z0x/9ecAMePlZRzoNGqi2OcOkMQ9d4AA59wBjjHAHWAYWGb6iUwgq3l+Z+9H2d37XXbj3Wn9ha0oiqIoqeUdwmrKD1GdTTcAAAAASUVORK5CYII="/>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -13,6 +13,8 @@
|
|||||||
<div class="label">Rotation</div>
|
<div class="label">Rotation</div>
|
||||||
<div class="value">
|
<div class="value">
|
||||||
<depth-input
|
<depth-input
|
||||||
|
icon="dc-angle"
|
||||||
|
size="8"
|
||||||
v-model="angle"
|
v-model="angle"
|
||||||
type="number"
|
type="number"
|
||||||
@input="inputFillTransform"
|
@input="inputFillTransform"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<div class="content" v-if="isShow" v-show="show">
|
<div class="content" v-if="isShow" v-show="show">
|
||||||
<!-- <basic-info :object="activeObject" /> -->
|
<!-- <basic-info :object="activeObject" /> -->
|
||||||
<fill-repeat :object="activeObject" v-if="isRepeat" />
|
<fill-repeat :object="activeObject" v-if="isRepeat" />
|
||||||
<!-- <shape-setting :object="activeObject" v-if="isShape && !isRepeat" /> -->
|
<shape-setting :object="activeObject" v-if="isShape && !isRepeat" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -27,10 +27,10 @@
|
|||||||
const layers = computed(() => layerManager.layers.value)
|
const layers = computed(() => layerManager.layers.value)
|
||||||
const activeObject = ref(null)
|
const activeObject = ref(null)
|
||||||
|
|
||||||
// const shapes = ['rect', 'line', 'path', 'triangle', 'polygon', 'ellipse']
|
const shapes = ['rect', 'line', 'path', 'triangle', 'polygon', 'ellipse']
|
||||||
// const isShape = computed(() => shapes.includes(activeObject.value?.type))
|
const isShape = computed(() => shapes.includes(activeObject.value?.type))
|
||||||
const isRepeat = computed(() => activeObject.value?.fill?.repeat === 'repeat')
|
const isRepeat = computed(() => activeObject.value?.fill?.repeat === 'repeat')
|
||||||
const isShow = computed(() => isRepeat.value)
|
const isShow = computed(() => isRepeat.value || isShape.value)
|
||||||
|
|
||||||
const updateActiveObject = () => {
|
const updateActiveObject = () => {
|
||||||
const layer = layerManager.getActiveLayer()
|
const layer = layerManager.getActiveLayer()
|
||||||
@@ -104,6 +104,10 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
padding: 0 1.4rem;
|
padding: 0 1.4rem;
|
||||||
|
margin-bottom: 1.6rem;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.v > div {
|
&.v > div {
|
||||||
|
|||||||
@@ -1,21 +1,121 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="shape-setting v">
|
<div class="shape-setting h">
|
||||||
<!-- <div>
|
<div>
|
||||||
<div class="label">填充颜色</div>
|
<div class="title">Position</div>
|
||||||
<div class="value">
|
<div class="content">
|
||||||
<el-color-picker
|
<div>
|
||||||
v-model="data.fill"
|
<depth-input
|
||||||
show-alpha
|
before="X"
|
||||||
:predefine="['transparent', '#000', '#f00', '#0f0', '#00f']"
|
type="number"
|
||||||
|
v-model="data.left"
|
||||||
|
@input="onInpot"
|
||||||
@change="onChange"
|
@change="onChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
<div>
|
||||||
|
<depth-input
|
||||||
|
before="Y"
|
||||||
|
type="number"
|
||||||
|
v-model="data.top"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div>
|
||||||
|
<depth-input
|
||||||
|
before="W"
|
||||||
|
type="number"
|
||||||
|
v-model="data.width"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<depth-input
|
||||||
|
before="H"
|
||||||
|
type="number"
|
||||||
|
v-model="data.height"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="title">Scale</div>
|
||||||
|
<div class="content">
|
||||||
|
<div>
|
||||||
|
<depth-input
|
||||||
|
type="number"
|
||||||
|
before="X"
|
||||||
|
after="%"
|
||||||
|
v-model="data.scaleX"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<depth-input
|
||||||
|
type="number"
|
||||||
|
before="Y"
|
||||||
|
after="%"
|
||||||
|
v-model="data.scaleY"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="title">Appearance</div>
|
||||||
|
<div class="content">
|
||||||
|
<div>
|
||||||
|
<span class="label">Opacity</span>
|
||||||
|
<depth-input
|
||||||
|
type="number"
|
||||||
|
after="%"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
step="1"
|
||||||
|
v-model="data.opacity"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="object.type === 'rect'">
|
||||||
|
<span class="label">Corner Radius</span>
|
||||||
|
<depth-input
|
||||||
|
type="number"
|
||||||
|
v-model="data.radius"
|
||||||
|
min="0"
|
||||||
|
step="1"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else></div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div>
|
||||||
|
<span class="label">Color</span>
|
||||||
|
<depth-input
|
||||||
|
type="color"
|
||||||
|
v-model="data.fill"
|
||||||
|
after="%"
|
||||||
|
@input="onInpot"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive } from 'vue'
|
import { ref, inject, computed, nextTick, onBeforeUnmount, reactive, watch } from 'vue'
|
||||||
import { ElColorPicker } from 'element-plus'
|
import { ElColorPicker } from 'element-plus'
|
||||||
import { getTransformScaleAngle } from '../../manager/ObjectManager'
|
import { getTransformScaleAngle } from '../../manager/ObjectManager'
|
||||||
import DepthOffsetTool from '../tools/depth-offset-tool.vue'
|
import DepthOffsetTool from '../tools/depth-offset-tool.vue'
|
||||||
@@ -32,22 +132,50 @@
|
|||||||
const id = computed(() => props.object.info.id)
|
const id = computed(() => props.object.info.id)
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
fill: '',
|
top: 0,
|
||||||
stroke: '',
|
left: 0,
|
||||||
strokeWidth: 0
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
scaleX: 1,
|
||||||
|
scaleY: 1,
|
||||||
|
opacity: 100,
|
||||||
|
radius: 0,
|
||||||
|
|
||||||
|
fill: ''
|
||||||
|
// stroke: '',
|
||||||
|
// strokeWidth: 0
|
||||||
})
|
})
|
||||||
const updateData = async () => {
|
const updateData = async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
data.top = Math.round(props.object.top)
|
||||||
|
data.left = Math.round(props.object.left)
|
||||||
|
data.width = Math.round(props.object.width)
|
||||||
|
data.height = Math.round(props.object.height)
|
||||||
|
data.scaleX = Math.round(props.object.scaleX * 100)
|
||||||
|
data.scaleY = Math.round(props.object.scaleY * 100)
|
||||||
|
data.opacity = Math.round(props.object.opacity * 100)
|
||||||
|
data.radius = Math.round(props.object.rx)
|
||||||
data.fill = props.object.fill
|
data.fill = props.object.fill
|
||||||
data.stroke = props.object.stroke
|
// data.stroke = props.object.stroke
|
||||||
data.strokeWidth = props.object.strokeWidth
|
// data.strokeWidth = props.object.strokeWidth
|
||||||
}
|
}
|
||||||
updateData()
|
updateData()
|
||||||
|
watch(() => props.object, updateData)
|
||||||
|
|
||||||
const onInpot = () => setPriority(false)
|
const onInpot = () => setPriority(false)
|
||||||
const onChange = () => setPriority(true)
|
const onChange = () => setPriority(true)
|
||||||
const setPriority = (isRecord: boolean) => {
|
const setPriority = (isRecord: boolean) => {
|
||||||
const options = { ...data }
|
const options = {
|
||||||
|
...data,
|
||||||
|
opacity: data.opacity / 100,
|
||||||
|
scaleX: data.scaleX / 100,
|
||||||
|
scaleY: data.scaleY / 100
|
||||||
|
}
|
||||||
|
if (props.object.type === 'rect') {
|
||||||
|
options['rx'] = data.radius
|
||||||
|
options['ry'] = data.radius
|
||||||
|
}
|
||||||
|
delete options.radius
|
||||||
objectManager.updateProperty(id.value, options, isRecord)
|
objectManager.updateProperty(id.value, options, isRecord)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +189,30 @@
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.shape-setting {
|
.shape-setting {
|
||||||
--details-item-margin-bottom: 1rem;
|
--details-item-margin-bottom: 1.6rem;
|
||||||
> div {
|
> div {
|
||||||
|
> .content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
> div {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 3rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
--depth-input-height: 2.4rem;
|
||||||
|
--depth-input-bg-color: rgba(249, 249, 250, 1);
|
||||||
|
--depth-input-border-color: rgba(230, 230, 231, 1);
|
||||||
|
--depth-input-decorate-color: rgba(69, 71, 84, 0.1);
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
> .label {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="depth-input">
|
<div class="depth-input" :class="{ color: isColor }">
|
||||||
<span class="decorate"></span>
|
<span class="decorate"></span>
|
||||||
<span v-show="icon" class="icon">
|
<span v-show="icon" class="icon">
|
||||||
<svg-icon :name="icon" :size="iconSize" size-unit="px" />
|
<svg-icon :name="icon" :size="iconSize" size-unit="px" />
|
||||||
@@ -13,12 +13,34 @@
|
|||||||
@copy.stop
|
@copy.stop
|
||||||
@keydown.stop
|
@keydown.stop
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
v-if="isColor"
|
||||||
|
readonly
|
||||||
|
type="text"
|
||||||
|
:value="colorObj.color"
|
||||||
|
@copy.stop
|
||||||
|
@keydown.stop
|
||||||
|
/>
|
||||||
|
<template v-if="isColor">
|
||||||
|
<span class="decorate marginl"></span>
|
||||||
|
<input
|
||||||
|
class="alpha"
|
||||||
|
type="number"
|
||||||
|
:value="Math.round(colorObj.alpha * 100)"
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
@input="(e) => onInput(e, 'alpha')"
|
||||||
|
@change="(e) => onChange(e, 'alpha')"
|
||||||
|
@copy.stop
|
||||||
|
@keydown.stop
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
<span v-show="after" class="after">{{ after }}</span>
|
<span v-show="after" class="after">{{ after }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, useAttrs, watch } from 'vue'
|
import { ref, useAttrs, watch, computed } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: { type: [String, Number] },
|
modelValue: { type: [String, Number] },
|
||||||
icon: { default: '', type: String },
|
icon: { default: '', type: String },
|
||||||
@@ -28,17 +50,169 @@
|
|||||||
})
|
})
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
const emit = defineEmits(['update:modelValue', 'input', 'change'])
|
const emit = defineEmits(['update:modelValue', 'input', 'change'])
|
||||||
const onInput = (e) => {
|
const isColor = computed(() => attrs.type === 'color')
|
||||||
var value = e.target.value
|
const colorObj = computed(() => {
|
||||||
if (attrs.type === 'number') value = Number(value)
|
if (isColor.value && props.modelValue) {
|
||||||
|
let color = parseColor(props.modelValue)
|
||||||
|
color.color = `#${toHex(color.r)}${toHex(color.g)}${toHex(color.b)}`
|
||||||
|
return color
|
||||||
|
}
|
||||||
|
return { color: '#fff', alpha: 1 }
|
||||||
|
})
|
||||||
|
|
||||||
|
const inputtime = ref(null)
|
||||||
|
const onInput = (e, type?: string) => {
|
||||||
|
clearTimeout(inputtime.value)
|
||||||
|
inputtime.value = setTimeout(() => {
|
||||||
|
const value = handleInputChange(e, type)
|
||||||
emit('update:modelValue', value)
|
emit('update:modelValue', value)
|
||||||
emit('input', value)
|
emit('input', value)
|
||||||
|
}, 10)
|
||||||
}
|
}
|
||||||
const onChange = (e) => {
|
const changetime = ref(null)
|
||||||
var value = e.target.value
|
const onChange = (e, type?: string) => {
|
||||||
if (attrs.type === 'number') value = Number(value)
|
clearTimeout(changetime.value)
|
||||||
|
changetime.value = setTimeout(() => {
|
||||||
|
const value = handleInputChange(e, type)
|
||||||
emit('update:modelValue', value)
|
emit('update:modelValue', value)
|
||||||
emit('change', value)
|
emit('change', value)
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
// 处理输入事件
|
||||||
|
const handleInputChange = (e, type?: string) => {
|
||||||
|
var value = e.target.value
|
||||||
|
if (attrs.type === 'number') value = Number(value)
|
||||||
|
if (isColor.value) {
|
||||||
|
const rgba = { ...colorObj.value }
|
||||||
|
if (type === 'alpha') {
|
||||||
|
let a = value / 100
|
||||||
|
value = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${a})`
|
||||||
|
} else {
|
||||||
|
let { r, g, b } = parseColor(value)
|
||||||
|
value = `rgba(${r}, ${g}, ${b}, ${rgba.a})`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseColor(colorString) {
|
||||||
|
// 处理 rgba/rgb
|
||||||
|
const rgbaMatch = colorString.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/i)
|
||||||
|
if (rgbaMatch) {
|
||||||
|
return {
|
||||||
|
type: 'rgb',
|
||||||
|
r: parseInt(rgbaMatch[1]),
|
||||||
|
g: parseInt(rgbaMatch[2]),
|
||||||
|
b: parseInt(rgbaMatch[3]),
|
||||||
|
a: rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1,
|
||||||
|
color: `#${toHex(rgbaMatch[1])}${toHex(rgbaMatch[2])}${toHex(rgbaMatch[3])}`,
|
||||||
|
alpha: rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理十六进制
|
||||||
|
const hexMatch = colorString.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i)
|
||||||
|
if (hexMatch) {
|
||||||
|
let hex = hexMatch[1]
|
||||||
|
if (hex.length === 3) {
|
||||||
|
hex = hex
|
||||||
|
.split('')
|
||||||
|
.map((c) => c + c)
|
||||||
|
.join('')
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'hex',
|
||||||
|
r: parseInt(hex.substring(0, 2), 16),
|
||||||
|
g: parseInt(hex.substring(2, 4), 16),
|
||||||
|
b: parseInt(hex.substring(4, 6), 16),
|
||||||
|
a: 1,
|
||||||
|
color: `#${hex}`,
|
||||||
|
alpha: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 hsl/hsla
|
||||||
|
const hslMatch = colorString.match(/hsla?\((\d+),\s*([\d.]+)%,\s*([\d.]+)%(?:,\s*([\d.]+))?\)/i)
|
||||||
|
if (hslMatch) {
|
||||||
|
const h = parseInt(hslMatch[1])
|
||||||
|
const s = parseInt(hslMatch[2])
|
||||||
|
const l = parseInt(hslMatch[3])
|
||||||
|
const a = hslMatch[4] ? parseFloat(hslMatch[4]) : 1
|
||||||
|
const rgb = hslToRgb(h, s, l)
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'hsl',
|
||||||
|
h,
|
||||||
|
s,
|
||||||
|
l,
|
||||||
|
r: rgb.r,
|
||||||
|
g: rgb.g,
|
||||||
|
b: rgb.b,
|
||||||
|
a: a,
|
||||||
|
color: `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`,
|
||||||
|
alpha: a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理颜色名称
|
||||||
|
const namedColors = {
|
||||||
|
red: '#ff0000',
|
||||||
|
green: '#00ff00',
|
||||||
|
blue: '#0000ff',
|
||||||
|
black: '#000000',
|
||||||
|
white: '#ffffff',
|
||||||
|
yellow: '#ffff00',
|
||||||
|
cyan: '#00ffff',
|
||||||
|
magenta: '#ff00ff',
|
||||||
|
transparent: 'rgba(0,0,0,0)'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (namedColors[colorString.toLowerCase()]) {
|
||||||
|
return parseColor(namedColors[colorString.toLowerCase()])
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseColor('#fff')
|
||||||
|
}
|
||||||
|
// 将 0-255 的数字转换为十六进制
|
||||||
|
function toHex(num) {
|
||||||
|
// 确保数字在 0-255 范围内
|
||||||
|
num = Math.min(255, Math.max(0, num))
|
||||||
|
// 转换为十六进制,并确保两位数
|
||||||
|
return num.toString(16).padStart(2, '0').toUpperCase()
|
||||||
|
}
|
||||||
|
// HSL 转 RGB
|
||||||
|
function hslToRgb(h, s, l) {
|
||||||
|
h = h / 360
|
||||||
|
s = s / 100
|
||||||
|
l = l / 100
|
||||||
|
|
||||||
|
let r, g, b
|
||||||
|
|
||||||
|
if (s === 0) {
|
||||||
|
r = g = b = l
|
||||||
|
} else {
|
||||||
|
const hue2rgb = (p, q, t) => {
|
||||||
|
if (t < 0) t += 1
|
||||||
|
if (t > 1) t -= 1
|
||||||
|
if (t < 1 / 6) return p + (q - p) * 6 * t
|
||||||
|
if (t < 1 / 2) return q
|
||||||
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
const q = l < 0.5 ? l * (1 + s) : l + s - l * s
|
||||||
|
const p = 2 * l - q
|
||||||
|
|
||||||
|
r = hue2rgb(p, q, h + 1 / 3)
|
||||||
|
g = hue2rgb(p, q, h)
|
||||||
|
b = hue2rgb(p, q, h - 1 / 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
r: Math.round(r * 255),
|
||||||
|
g: Math.round(g * 255),
|
||||||
|
b: Math.round(b * 255)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -46,37 +220,46 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid rgba(230, 230, 231, 1);
|
border: 1px solid var(--depth-input-border-color, rgba(230, 230, 231, 1));
|
||||||
border-radius: 1.7px;
|
border-radius: 2px;
|
||||||
height: 17px;
|
height: var(--depth-input-height, 20px);
|
||||||
|
background-color: var(--depth-input-bg-color, #fff);
|
||||||
padding: 0 4px 0 2px;
|
padding: 0 4px 0 2px;
|
||||||
|
&.color {
|
||||||
|
--depth-input-decorate-margin-right: 10px;
|
||||||
|
--depth-input-input-margin-right: 10px;
|
||||||
|
--depth-input-input-font-align: left;
|
||||||
|
--depth-input-after-color: rgba(181, 181, 181, 1);
|
||||||
|
}
|
||||||
> .decorate {
|
> .decorate {
|
||||||
width: 2px;
|
width: 2px;
|
||||||
background-color: rgba(230, 230, 231, 1);
|
background-color: var(--depth-input-decorate-color, rgba(230, 230, 231, 1));
|
||||||
border-radius: 3px;
|
border-radius: 2px;
|
||||||
height: 85%;
|
height: 75%;
|
||||||
margin-right: 4px;
|
margin-right: var(--depth-input-decorate-margin-right, 4px);
|
||||||
}
|
}
|
||||||
> .iconfont {
|
> .iconfont {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #000;
|
color: #000;
|
||||||
margin-right: 2px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
> .before {
|
> .before {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #000;
|
color: #000;
|
||||||
margin-right: 2px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
> .after {
|
> .after {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #000;
|
color: var(--depth-input-after-color, #000);
|
||||||
margin-left: 1px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
> input {
|
> input {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
width: 0;
|
width: 0;
|
||||||
|
height: 100%;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: right;
|
margin-right: var(--depth-input-input-margin-right, 0);
|
||||||
|
text-align: var(--depth-input-input-font-align, right);
|
||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@@ -87,6 +270,28 @@
|
|||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
&.alpha {
|
||||||
|
flex: 0.4;
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
&[type='color'] {
|
||||||
|
flex: 0.5;
|
||||||
|
border-radius: 2px;
|
||||||
|
height: 70%;
|
||||||
|
border: 1px solid rgb(42, 42, 42);
|
||||||
|
display: block;
|
||||||
|
&::-webkit-color-swatch-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-color-swatch {
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
const tools = ref([
|
const tools = ref([
|
||||||
{ name: TOOLS.SELECT, icon: 'c-select', iconSize: 16, disabled: ref(false) },
|
{ name: TOOLS.SELECT, icon: 'c-select', iconSize: 16, disabled: ref(false) },
|
||||||
{ name: TOOLS.MOVE, icon: 'c-move', iconSize: 18, disabled: ref(false) },
|
{ name: TOOLS.MOVE, icon: 'c-move', iconSize: 18, disabled: ref(false) },
|
||||||
{ name: TOOLS.TEXT, icon: 'c-text', iconSize: 18, disabled: ref(false) },
|
{ name: TOOLS.TEXT, icon: 'c-text', iconSize: 22, disabled: ref(false) },
|
||||||
{ type: 'line' },
|
{ type: 'line' },
|
||||||
{
|
{
|
||||||
name: TOOLS.UNDO,
|
name: TOOLS.UNDO,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
@paste.prevent
|
@paste.prevent
|
||||||
@keydown.stop
|
@keydown.stop
|
||||||
></div>
|
></div>
|
||||||
<div class="tools" @mousedown="onMouseDown">
|
<div class="tools" @mousedown="onMouseDown" v-if="active">
|
||||||
<myTextTools :textStyle="data.textStyle"></myTextTools>
|
<myTextTools :textStyle="data.textStyle"></myTextTools>
|
||||||
</div>
|
</div>
|
||||||
<span class="delete" @mousedown.stop @click="emit('delete-node')" v-show="active">
|
<span class="delete" @mousedown.stop @click="emit('delete-node')" v-show="active">
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
}
|
}
|
||||||
.fontFamily{
|
.fontFamily{
|
||||||
width: 103px;
|
width: 103px;
|
||||||
|
--el-text-color-regular: #000
|
||||||
}
|
}
|
||||||
.color{
|
.color{
|
||||||
width: 55px;
|
width: 55px;
|
||||||
|
|||||||
Reference in New Issue
Block a user