Files
aida_front/src/component/Canvas/CanvasEditor/components/SelectMenuPanel/RepeatSetting.vue

189 lines
5.2 KiB
Vue
Raw Normal View History

2026-01-02 11:24:11 +08:00
<template>
<div class="repeat-setting">
2026-01-13 14:41:20 +08:00
<div class="title">{{ t("Canvas.repeatSetting") }}</div>
2026-01-02 11:24:11 +08:00
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.angle") }}</span>
<angle-tool
:angle="angle"
@input="(e) => emit('inputFillAngle', e)"
@change="(e) => emit('changeFillAngle', e)"
2026-01-13 14:41:20 +08:00
style-type="2"
2026-01-02 11:24:11 +08:00
/>
</div>
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.scale") }}</span>
<slider
:min="1"
2026-01-23 15:24:39 +08:00
:max="1000"
2026-01-02 11:24:11 +08:00
:step="1"
is-input
:tipFormatter="(v) => `${scale}%`"
:value="scale"
@input="inputFillScale"
@change="changeFillScale"
/>
</div>
<div class="repeat-setting-item">
<span class="label">Gap X</span>
<slider
:min="0"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapX"
2026-01-20 14:10:10 +08:00
@input="(e) => emit('inputFillGap', e, gapY)"
@change="(e) => emit('changeFillGap', e, gapY)"
2026-01-02 11:24:11 +08:00
/>
</div>
<div class="repeat-setting-item">
<span class="label">Gap Y</span>
<slider
:min="0"
:max="1000"
:step="1"
is-input
:tipFormatter="(v) => `${v}px`"
:value="gapY"
2026-01-20 14:10:10 +08:00
@input="(e) => emit('inputFillGap', gapX, e)"
@change="(e) => emit('changeFillGap', gapX, e)"
2026-01-02 11:24:11 +08:00
/>
</div>
<div class="repeat-setting-item">
<span class="label">{{ t("Canvas.offset") }}</span>
<offset-tool
2026-01-23 15:24:39 +08:00
:left="offset.x"
:top="offset.y"
@input="inputFillOffset"
@change="changeFillOffset"
2026-01-13 14:41:20 +08:00
:show-dish="false"
/>
</div>
<div class="repeat-setting-item offset">
<offset-tool
2026-01-23 15:24:39 +08:00
:left="offset.x"
:top="offset.y"
@input="inputFillOffset"
@change="changeFillOffset"
2026-01-13 14:41:20 +08:00
:show-input="false"
2026-01-02 11:24:11 +08:00
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, computed } from "vue";
import { getTransformScaleAngle } from "../../utils/helper";
import AngleTool from "../tools/AngleTool.vue";
import OffsetTool from "../tools/OffsetTool.vue";
import Slider from "../tools/Slider.vue";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
2026-01-23 15:24:39 +08:00
const emit = defineEmits([
"inputFillAngle",
"changeFillAngle",
"inputFillOffset",
"changeFillOffset",
"inputFillScale",
"changeFillScale",
"inputFillGap",
"changeFillGap",
]);
2026-01-02 11:24:11 +08:00
const props = defineProps({
object: {
required: true,
type: Object,
},
});
const angle = computed(
() => getTransformScaleAngle(props.object.fill?.patternTransform).angle
);
const gapX = computed(() => props.object.fill_?.gapX || 0);
const gapY = computed(() => props.object.fill_?.gapY || 0);
2026-01-23 15:24:39 +08:00
// 缩放比例
const scale = computed(() => {
const object = props.object;
const patternTransform = object.fill?.patternTransform;
const scaleValue = getTransformScaleAngle(patternTransform).scale;
const scaleX = scaleValue / (object.width / object.fill_.width / 5);
const scaleY = scaleValue / (object.height / object.fill_.height / 5);
const scaleXY = object.width > object.height ? scaleX : scaleY;
return Number(Number(scaleXY * 100).toFixed(2));
});
const inputFillScale = (e) => setFillScale(e, true);
const changeFillScale = (e) => setFillScale(e, false);
const setFillScale = (e, isInput) => {
const object = props.object;
2026-01-02 11:24:11 +08:00
const scale = e / 100;
2026-01-23 15:24:39 +08:00
const scaleX = (object.width / object.fill_.width / 5) * scale;
const scaleY = (object.height / object.fill_.height / 5) * scale;
const scaleXY = object.width > object.height ? scaleX : scaleY;
emit(isInput ? "inputFillScale" : "changeFillScale", scaleXY);
2026-01-02 11:24:11 +08:00
};
2026-01-23 15:24:39 +08:00
// 偏移量
const offset = computed(() => {
const object = props.object;
const patternTransform = object.fill?.patternTransform;
const scale = getTransformScaleAngle(patternTransform).scale;
const offsetX = object.fill?.offsetX;
const offsetY = object.fill?.offsetY;
const twidth = object.fill_?.width;
const theight = object.fill_?.height;
const x = ((offsetX - (twidth * scale) / 2) * 100) / object.width;
const y = ((offsetY - (theight * scale) / 2) * 100) / object.height;
return { x, y };
});
const inputFillOffset = (e) => setFillOffset(e, true);
const changeFillOffset = (e) => setFillOffset(e, false);
const setFillOffset = (e, isInput) => {
const { left, top } = e;
const object = props.object;
const patternTransform = object.fill?.patternTransform;
const scale = getTransformScaleAngle(patternTransform).scale;
const x = (left / 100) * object.width + (object.fill_?.width * scale) / 2;
const y = (top / 100) * object.height + (object.fill_?.height * scale) / 2;
emit(isInput ? "inputFillOffset" : "changeFillOffset", { x, y });
2026-01-02 11:24:11 +08:00
};
</script>
<style scoped lang="less">
.repeat-setting {
user-select: none;
2026-01-13 14:41:20 +08:00
width: 228px;
2026-01-23 15:24:39 +08:00
overflow: hidden;
2026-01-13 14:41:20 +08:00
> .title {
line-height: 35px;
font-size: 14px;
text-align: center;
margin-top: -12px;
margin-bottom: 3px;
}
2026-01-02 11:24:11 +08:00
> .repeat-setting-item {
display: flex;
align-items: center;
2026-01-13 14:41:20 +08:00
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
&.offset {
justify-content: center;
}
2026-01-02 11:24:11 +08:00
> .label {
2026-01-13 14:41:20 +08:00
min-width: 68px;
font-size: 12px;
2026-01-02 11:24:11 +08:00
}
2026-01-13 14:41:20 +08:00
&:not(.offset) > div {
2026-01-02 11:24:11 +08:00
width: 120px;
2026-01-13 14:41:20 +08:00
flex: 1;
}
> .slider {
--slider-thumb-color1: #000;
--slider-thumb-color2: #eee;
2026-01-02 11:24:11 +08:00
}
}
}
</style>