Files
aida_front/src/component/Canvas/CanvasEditor/components/PalletPanel/pallet.vue
X1627315083 972743d3b8 fix
2026-01-23 16:58:03 +08:00

666 lines
19 KiB
Vue

<template>
<div class="pallet" ref="palletRef">
<div class="palletColo" @click="openPallet">
<div v-show="!selectColor.gradient" class="palletBackColor" :title="selectColor.name" :style="{'background-color':selectColor.hex}">
{{ selectColor.hex }}
</div>
<div v-show="selectColor.gradient" class="palletBackColor" :style="{'background-image':`linear-gradient(${selectColor.gradient?.angle}deg,${setGradient(selectColor.gradient)})`}">
</div>
</div>
<div class="palletBox">
<div class="color_setting_block" @click.stop>
<Chrome class="chrome_color" v-model="color_"></Chrome>
<div class="color_setting_operateSingle">
<div class="color_setting_btn" :class="{active:!color?.gradient?.gradientShow}">{{ $t('ColorboardUpload.Single') }}</div>
<a-switch :checked="color?.gradient?.gradientShow" @click="setOperate"/>
<div class="color_setting_btn" :class="{active:color?.gradient?.gradientShow}">{{ $t('ColorboardUpload.Gradual') }}</div>
</div>
<div class="color_setting_operate" v-if="color?.gradient?.gradientShow">
<div class="color_setting_operate_item color_setting_operate_control">
<div class="operate_item_box">
<div>{{ $t('ColorboardUpload.Alignment') }}</div>
</div>
<div class="operate_item_box operate_item_angle">
<div class="operate_item_angle_box" @mousedown="mousedownGradientAngle(getMousePosition($event,false))" @touchstart="mousedownGradientAngle(getMousePosition($event,true))">
<div :style="{'transform':`rotate(${color.gradient.angle}deg)`}"></div>
</div>
</div>
<div class="operate_item_box operate_item_delete">
<i class="fi fi-rr-trash" @click="deleteGradientItem"></i>
</div>
</div>
<div class="color_setting_operate_item color_setting_operate_input">
<div class="color_setting_operate_bg" @click="addGradient($event)" :style="{'background-image':color?.gradient?`linear-gradient(90deg,${setGradient(color.gradient)})`:'none'}">
</div>
<div v-for="item,index in color.gradient.gradientList" :key="item" class="color_setting_operate_btn" :class="{'active':index == color.gradient.selectIndex}" :style="{'left':item.left,'background-color':`rgba(${item.rgba.r},${item.rgba.g},${item.rgba.b},${item.rgba.a})`}" @mousedown="mousedownGradient(getMousePosition($event,false),item,index,)" @touchstart="mousedownGradient(getMousePosition($event,true),item,index,)"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent,computed,ref,watch,nextTick,onMounted,onUnmounted,toRefs, reactive} from 'vue'
import { useStore } from "vuex";
import { useI18n } from 'vue-i18n'
import { message,Upload} from 'ant-design-vue';
import { Sketch, Chrome} from '@ans1998/vue3-color'
import { getMousePosition } from "@/tool/mdEvent";
import { rgbaToHex } from "@/tool/util"
import { color } from 'echarts/core';
export default defineComponent({
components:{
Chrome,
},
props:{
selectColor:{
type:Object,
default:()=>{}
},
},
emits:['selectUplpadColor'],
setup(props,{emit}) {
const {t} = useI18n()
const store = useStore();
const palletData = reactive({
palletShow: true,
palletList:[],
color_:{} as any,
color:{} as any,
updataSelectColorTime:null as any,
gradient:{
gradientList:[
{
rgba:{
r:117,
g:119,
b:255,
a:1,
},
left:'0%'
},{
rgba:{
r:0,
g:222,
b:152,
a:1,
},
left:'100%'
},
],
angle:45,
selectIndex:-1,
gradientShow:false,
},
setGradient:computed(()=>{
return (gradient:any)=>{
let gradientStr = ''
if(!gradient?.gradientList)return
gradient.gradientList.sort((a:any, b:any) => {
let aArr = a.left.split('%')[0]
let bArr = b.left.split('%')[0]
return aArr - bArr;
});
gradient.gradientList.forEach((item:any,index:any)=>{
let str = ','
if(gradient.gradientList.length == index+1)str = ''
let rgba = item.rgba?item.rgba:{r:255,g:255,b:255}
gradientStr += `rgba(${rgba.r},${rgba.g},${rgba.b},${rgba.a}) ${item.left}${str}`
})
return `${gradientStr}`
}
})
})
const getpalletListDom = reactive({
})
const palletRef = ref(null)
watch(()=>palletData.color_,(newVal:any)=>{
if(newVal?.rgba?.r == null)return
if(palletData.color?.gradient?.gradientShow){
palletData.color.gradient.gradientList[palletData.color.gradient.selectIndex].rgba = {
r:newVal.rgba.r,
g:newVal.rgba.g,
b:newVal.rgba.b,
a:newVal.rgba.a,
}
}else{
palletData.color = newVal
}
})
watch(()=>palletData.color,(newVal:any)=>{
if(JSON.stringify(props.selectColor) != JSON.stringify(newVal)){
newVal.name = ''
newVal.tcx = ''
let rgba = [newVal.rgba.r,newVal.rgba.g,newVal.rgba.b]
let hex = rgbaToHex(rgba)
newVal.hex = hex
emit('selectUplpadColor',newVal)
}
},{deep: true })
const setOperate = ()=>{
if(!palletData.color.rgba)return message.info(t('DesignDetailAlter.jsContent7'))
palletData.color.rgba = palletData.color?.rgba?.r != null?palletData.color.rgba:{r:0,g:0,b:0,a:1}
palletData.gradient.selectIndex = 0
palletData.gradient.gradientShow = true
if(!palletData.color.gradient){
if(palletData.color.rgba.r){
palletData.gradient.gradientList[palletData.gradient.selectIndex].rgba = {
r:palletData.color.rgba.r,
g:palletData.color.rgba.g,
b:palletData.color.rgba.b,
a:1,
}
}
palletData.color.gradient = JSON.parse(JSON.stringify(palletData.gradient))
}else{
palletData.color.rgba = palletData.color.gradient.gradientList[0].rgba
palletData.color.gradient = null
}
}
const deleteGradientItem = ()=>{
if(palletData.color.gradient.gradientList.length <= 2)return
palletData.color.gradient.gradientList.splice(palletData.color.gradient.selectIndex,1)
}
const addGradient = (event:any)=>{
let gradientWidth = event.target.clientWidth
let left:any = event.offsetX/gradientWidth
palletData.color.gradient.gradientList.push({
rgba:palletData.color_.rgba,
left:left.toFixed(2)*100+'%'
})
}
const mousedownGradientAngle = (event:any)=>{
// isMoible() true为移动端
let domPosition = event.target.getBoundingClientRect()
let position = {
x:domPosition.x+domPosition.width/2,
y:domPosition.y+domPosition.height/2,
}
let angle
let mousedown = function(event:any){
let e = getMousePosition(event,false)
mouseDownOperation(e)
}
let touchstart = function(event:any){
let e = getMousePosition(event,true)
mouseDownOperation(e)
}
let mouseDownOperation = (e:any)=>{
let X = position.x
let Y = position.y
let x = (e.clientX) - X
let y = Y -( e.clientY)
angle = Math.atan2(x,y)*(180 / Math.PI)
// this.colorList[this.selectIndex].gradient = JSON.parse(JSON.stringify(this.gradient))
palletData.color.gradient.angle = angle
}
let mouseupGradientAngle = ()=>{
window.removeEventListener('touchmove',touchstart)
window.removeEventListener('touchend',mouseupGradientAngle)
window.removeEventListener('mousemove',mousedown)
window.removeEventListener('mouseup',mouseupGradientAngle)
}
window.addEventListener('touchmove',touchstart)
window.addEventListener('touchend',mouseupGradientAngle)
window.addEventListener('mousemove',mousedown)
window.addEventListener('mouseup',mouseupGradientAngle)
}
const mousedownGradient = (event:any,item:any,index:number)=>{
palletData.color.gradient.selectIndex = index
// this.selectColor = {rgba:gradientRgba,hex:hex} //顔色选择器默认颜色
let gradientWidth = (palletRef.value.querySelector('.color_setting_operate_bg') as any).clientWidth
let position = {
x:event.clientX,
left:event.target.style.left?event.target.style.left.split('%')[0]:0
}
let mousedown = function(event:any){
let e = getMousePosition(event,false)
mousedownGradient(e)
}
let touchstart = function(event:any){
let e = getMousePosition(event,true)
mousedownGradient(e)
}
let mousedownGradient = (e:any)=>{
let left = ((e.clientX) - position.x)/gradientWidth*100+Number(position.left)
left = (left<0?0:left>100?100:left)
item.left = left+'%'
}
let mouseupGradientAngle = ()=>{
window.removeEventListener('touchmove',touchstart)
window.removeEventListener('touchend',mouseupGradientAngle)
window.removeEventListener('mousemove',mousedown)
window.removeEventListener('mouseup',mouseupGradientAngle)
}
window.addEventListener('touchmove',touchstart)
window.addEventListener('touchend',mouseupGradientAngle)
window.addEventListener('mousemove',mousedown)
window.addEventListener('mouseup',mouseupGradientAngle)
}
const selectImgItem = ()=>{
}
const openPallet = ()=>{
if(palletData.palletShow && props.selectColor?.rgba?.r != null){
if(props.selectColor.gradient){
palletData.color_.rgba = props.selectColor.gradient.gradientList[0].rgba
}else{
palletData.color_ = JSON.parse(JSON.stringify(props.selectColor))
palletData.gradient.gradientShow = false
}
palletData.color = JSON.parse(JSON.stringify(props.selectColor))
}else{
}
}
// 点击外部区域关闭颜色选择器
const handleClickOutside = (event: Event) => {
const target = event.target as HTMLElement;
const colorSettingBlock = palletRef.value.querySelector('.color_setting_block');
const palletColo = palletRef.value.querySelector('.palletColo');
// 如果点击的是 .palletColo 或 .color_setting_block 内部,则不关闭
if (palletData.palletShow && colorSettingBlock &&
!colorSettingBlock.contains(target) &&
!palletColo?.contains(target)) {
palletData.palletShow = false;
}
}
onMounted(()=>{
// 添加点击外部区域监听器
// document.addEventListener('click', handleClickOutside);
nextTick().then(()=>{
const backIcon = document.createElement('div');
backIcon.classList.add('vc-sketch-color-wrap')
let dropperDom = palletRef.value.getElementsByClassName('vc-chrome-fields-wrap')[0]
dropperDom.appendChild(backIcon);
backIcon.addEventListener('click',async ()=>{
try {
const dropper = new EyeDropper();
const result = await dropper.open();
let hex = result.sRGBHex.replace("#", "");
// 将十六进制颜色码拆分成红、绿、蓝三个部分
const r = parseInt(hex.substring(0, 2), 16);
const g = parseInt(hex.substring(2, 4), 16);
const b = parseInt(hex.substring(4, 6), 16);
palletData.color = {rgba:{r:r,g:g,b:b,a:1},hex:result.sRGBHex}
// return `rgb(${r}, ${g}, ${b})`;
// box.style.backgroundColor = label.textContent = result.sRGBHex;
} catch (e) {
message.info(t('DesignDetailAlter.jsContent1'))
}
})
openPallet();
})
})
onUnmounted(()=>{
// 清理事件监听器
// document.removeEventListener('click', handleClickOutside);
})
return{
...toRefs(palletData),
...toRefs(getpalletListDom),
palletRef,
openPallet,
selectImgItem,
setOperate,
deleteGradientItem,
addGradient,
mousedownGradientAngle,
mousedownGradient,
getMousePosition,
}
},
provide() {
return {
}
},
})
</script>
<style lang="less" scoped>
.pallet{
// position: absolute;
width: 100%;
user-select: none;
> .palletColo{
width: 100%;
height: 7rem;
border-radius: .5rem;
border: 1px solid #000;
padding: .5rem .6rem;
cursor: pointer;
> .palletBackColor{
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
> .palletBox{
margin-top: 1.5rem;
width: 100%;
z-index: 2;
> .color_setting_block{
margin: auto;
background: linear-gradient(70deg, #eee4f3, #f3f4e6);
width: 100%;
// border-radius: calc(1rem*1.2);
overflow: hidden;
box-shadow: 2px 2px 8px rgba(0,0,0,.3);
.vc-chrome{
background: rgba(0,0,0,0);
box-shadow:none;
}
:deep(.chrome_color){
width: 100%;
overflow: hidden;
.vc-chrome-saturation-wrap{
width: 30rem;
height: 30rem;
margin: 2rem auto;
padding-bottom: 0;
}
.vc-saturation-pointer{
pointer-events: none;
}
.vc-chrome-body{
padding: 0;
width: 90%;
margin: 2 auto;
margin: 0 auto;
background: rgba(0,0,0,0);
margin-bottom: 3rem;
// display: none;
.vc-chrome-fields-wrap{
margin-top: 5%;
padding: 0;
position: relative;
.vc-chrome-toggle-btn{
width: calc(3.2rem*1.2);
.vc-chrome-toggle-icon{
height: auto;
margin-right: calc(-0.4rem*1.2);
margin-top: calc(0rem*1.2);
display: flex;
flex-direction: column;
align-items: center;
svg{
width: calc(2.4rem*1.2) !important;
height: calc(2.4rem*1.2) !important;
}
}
}
.vc-chrome-fields{
.vc-chrome-field{
padding-left: calc(.6rem*1.2);
}
.vc-input__label{
font-size: calc(1.6rem*1.2);
}
.vc-input__input{
font-size: 2rem;
height: 4rem;
}
}
.ant-upload-list{
}
.vc-sketch-color-wrap{
background-image: url(@/assets/images/homePage/dropper.png);
background-size: 3rem;
background-repeat: no-repeat;
background-position: 50%;
cursor: pointer;
margin: 0;
width: 4rem;
height: 4rem;
padding: calc(.7rem*1.2);
border: 1px solid;
position: absolute;
bottom: -2rem;
right: 0rem;
border-radius: calc(.5rem*1.2);
}
.vc-chrome-fields{
.vc-input__label{
margin-top: calc(1rem*1.2);
}
}
.vc-chrome-fields:nth-child(2){
>:last-of-type {
display: none;
}
}
.vc-chrome-fields:nth-child(3){
>:last-of-type {
display: none;
}
}
}
.vc-chrome-controls{
align-items: center;
flex-direction: row-reverse;
.vc-chrome-color-wrap{
// width: 3.6rem*1.2);
margin-left: calc(2rem*1.2);
width: auto;
.vc-chrome-active-color{
border-radius: 50%;
}
.vc-chrome-active-color,.vc-checkerboard{
width: calc(3rem*1.2);
height: calc(3rem*1.2);
}
}
.vc-chrome-hue-wrap,.vc-chrome-alpha-wrap{
.vc-hue{
border-radius: 15px;
}
.vc-alpha{
border-radius: 15px;
overflow: hidden;
}
height: 2rem;
margin: 0;
.vc-hue-pointer{
transform: translateX(-1.25rem);
}
.vc-hue-picker{
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
transform: translate(0px,-3px);
}
}
.vc-chrome-alpha-wrap{
display: none;
}
}
}
.vc-chrome-saturation-wrap .vc-saturation-circle{
width: calc(1rem*1.2);
height: calc(1rem*1.2);
}
}
.color_block{
// margin-top: calc(1rem;
// display: flex;
// justify-content: space-between;
// font-size: calc(1.6rem;
width: 100%;
padding: 0 5%;
padding-bottom: 5%;
margin: calc(0.5rem*1.2) auto;
display: flex;
justify-content: space-between;
align-items: center;
.color_right{
width: 13rem;
font-size: calc(1.2rem*1.2);
color: #666666;
.color_rgb_block{
display: flex;
.rgb_item{
margin-left: calc(.2rem*1.2);
}
}
}
.color_left{
cursor: pointer;
color: rgb(153, 153, 153);
}
.color_right,.color_left{
>div{
display: flex;
align-items: center;
}
.color_HEX_block,.color_rgb_block{
padding: .25rem .6rem;
box-shadow: inset 0 0 0 1px #ccc;
border-radius: .5rem;
justify-content: space-around;
text-transform:uppercase;
.color_block_bg{
width: 1.8rem;
height: 2.5rem;
// margin-right: .5rem;
display: flex;
justify-content: space-between;
}
}
.color_block_bg{
}
}
}
.color_setting_operateSingle{
text-align: center;
margin: 1rem 0;
display: flex;
justify-content: center;
.color_setting_btn{
margin: 0 1rem;
color: rgba(0, 0, 0, 0.5);
&.active{
color: rgba(0, 0, 0, 0.7);
font-weight: 900;
}
}
}
.color_setting_operate{
*{
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
}
.color_setting_operate_item{
display: flex;
justify-content: space-around;
align-items: center;
.operate_item_box{
}
}
.color_setting_operate_control{
.operate_item_delete,.operate_item_angle{
cursor: pointer;
}
.operate_item_delete{
i{
display: flex;
font-size: 3rem;
}
}
.operate_item_angle{
.operate_item_angle_box{
border-radius: 50%;
width: 4rem;
height: 4rem;
border: solid 2px #000;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
>div{
height: 100%;
width: 1rem;
position: relative;
pointer-events:none;
}
>div::before{
position: absolute;
content: "";
top: 0.2rem;
left: 0;
width: 1rem;
height: 1rem;
border-radius: 50%;
background: #000;
}
}
}
}
.color_setting_operate_input{
width: 80%;
// padding: 0 10%;
margin: 1.2rem 10%;
border-radius: 10%;
position: relative;
height: 2.5rem;
.color_setting_operate_bg{
border-radius: .5rem;
width: 100%;
height: 2.5rem;
background: #fff;
position: absolute;
}
}
.color_setting_operate_btn{
position: absolute;
top: 50%;
transform: translate(-50%,-50%);
left: 0;
width: 1rem;
height: 110%;
border: .2rem solid;
border-radius: .5rem;
cursor: pointer;
box-sizing: content-box;
z-index: 2;
&.active{
border: .3rem solid;
}
}
.color_setting_operate_btn:hover{
border: .3rem solid;
}
}
}
}
}
</style>