Files
aida_front/src/component/Canvas/canvasExample.vue

626 lines
14 KiB
Vue
Raw Normal View History

<script setup>
2026-01-16 10:29:03 +08:00
import { ref } from "vue";
import CanvasEditor from "./CanvasEditor/index.vue";
import RedGreenModeExample from "./RedGreenModeExample.vue";
import ExistsImageList from "@/component/Canvas/ExistsImageList/index.vue";
import ToolButton from "@/component/Canvas/ExistsImageList/ToolButton.vue";
// 当前显示的组件
const canvasEditor = ref();
const currentView = ref("canvasEditor"); // 默认显示红绿图示例 canvasEditor redGreenExample
2026-01-16 15:16:33 +08:00
const clothingMinIOPath =
"aida-users/24299/sketchboard/female/Outwear/32d2485c-90fa-43d0-bc31-e59aaea466ba.png";
2026-01-16 10:29:03 +08:00
const clothingImageUrl = "/src/assets/images/canvas/xiangao.png";
const clothingImageUrlInit = "/src/assets/images/canvas/xiangaofenge.png";
const imageData = [
{
name: "风景照片",
type: "风景",
imgList: [
{
url: "https://www.minio-api.aida.com.hk/aida-users/83/printboard/7a0cccfc-1e3c-4c38-af65-d6179f21a267.png?response-content-type=image%2Fpng&response-content-disposition=inline&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20250723%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20250723T025046Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=3612d6c168207bebdae2fa7c7c2c86ea0f48358b99b8b41dec9e2ff15e197e15",
name: "山景",
},
{ url: "/src/assets/work/2.PNG", name: "海景" },
],
},
{
name: "人物照片",
type: "人物",
imgList: [
{ url: "/src/assets/work/3.PNG", name: "肖像1" },
{ url: "/src/assets/work/5.PNG", name: "肖像2" },
],
},
{
name: "衣服照片",
type: "衣服",
imgList: [
{ url: "/src/assets/work/3.PNG", name: "肖像1" },
{ url: "/src/assets/work/5.PNG", name: "肖像2" },
],
},
{
name: "裤子照片",
type: "裤子",
imgList: [
{ url: "/src/assets/work/IMG_0001.PNG", name: "肖像1" },
{ url: "/src/assets/work/IMG_0008.PNG", name: "肖像2" },
],
},
];
const handleImageSelect = (selectedImage) => {
console.log("选中的图片:", selectedImage);
console.log(selectedImage);
// selectedImage 包含url, name, categoryName, categoryType, originalItem
};
// 切换视图
function switchView(view) {
currentView.value = view;
}
// 定义编辑器配置
const editorConfig = {
width: 800,
height: 600,
backgroundColor: "#ffffff", // 画布背景色
};
const exportImage = async () => {
if (canvasEditor.value) {
const base64 = await canvasEditor.value.exportImage({
isContainFixed: true, // 是否导出底图
isContainFixedOther: true, // 是否导出其他固定图层
isContainBg: false, // 是否导出背景
isEnhanceImg: false, // 是否导出增强图片
});
// 模拟下载图片
const link = document.createElement("a");
link.href = base64;
link.download = "canvas_image.png"; // 设置下载文件名
document.body.appendChild(link);
link.click(); // 触发下载
document.body.removeChild(link); // 下载后移除链接元素
}
};
// 导出颜色图层
const exportColorLayer = async () => {
if (canvasEditor.value) {
const colorLayer = await canvasEditor.value.exportColorLayer();
console.log("导出颜色图层:", colorLayer);
// 模拟下载图片
const link = document.createElement("a");
link.href = colorLayer.base64;
link.download = "canvas_image.png"; // 设置下载文件名
document.body.appendChild(link);
link.click(); // 触发下载
document.body.removeChild(link); // 下载后移除链接元素
}
};
// 导出所有信息
const exportExtraInfo = async () => {
if (canvasEditor.value) {
const extraInfo = await canvasEditor.value.exportExtraInfo();
console.log("==========导出信息:", extraInfo);
}
};
// 更新其他图层颜色
const updateOtherLayersColor = async () => {
const obj = {
color: { rgba: { r: 255, g: 255, b: 0, a: 1 } },
};
await canvasEditor?.value?.updateOtherLayers?.(obj);
};
// 更新其他图层印花
const updateOtherLayersPrint = async () => {
// document.querySelector(".app-container").style.width = "50vw"
const obj = {
printObject: {
prints: [
{
ifSingle: true,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [250, 780],
scale: [0.3, 0.4],
angle: 0,
},
],
},
};
await canvasEditor?.value?.updateOtherLayers?.(obj);
};
const changeCanvas = (command) => {
console.log(command);
};
const changeImageUrl = "/src/assets/work/1.PNG";
const loadImageUrlToLayer = async () => {
try {
const layerToLayer1 = canvasEditor?.value?.layers?.[0]?.id;
const layerId = await canvasEditor?.value?.addImageToLayer?.(
changeImageUrl,
{
layerId: layerToLayer1, // 指定添加到的图层ID
imageMode: "contains", // 设置图片包含在画布内
}
);
console.log("新图层ID", layerId);
} catch (error) {
console.error("加载图片到图层失败:", error);
}
};
// 自定义工具方法
function exportAsPNG() {
console.log("导出PNG");
// 实现导出PNG逻辑
exportImage();
}
function saveCanvas() {
console.log("保存项目");
// 实现保存画布逻辑
const json = canvasEditor.value.getJSON();
localStorage.setItem("canvasProject", json);
}
function canvasProject() {
console.log("读取项目");
// 实现读取画布逻辑
const json = localStorage.getItem("canvasProject");
if (json) {
console.log("读取的项目JSON", JSON.parse(json)?.layers);
canvasEditor.value.loadJSON(json);
} else {
console.warn("没有找到保存的画布项目");
}
}
const exportJSON = () => {
console.log("导出JSON");
// 实现导出JSON逻辑
const json = canvasEditor.value.getJSON();
// 导出JSON文件
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "canvas_project.json";
a.click();
URL.revokeObjectURL(url);
};
// 复制JSON
const copyJSON = () => {
console.log("复制JSON");
// 实现复制JSON逻辑
const json = canvasEditor.value.getJSON();
// 复制JSON到剪贴板
navigator.clipboard.writeText(json);
};
const getLayers = () => {
console.log("==========layers", canvasEditor.value?.layers);
};
// 处理自定义工具点击
const handleCustomToolClick = (tool) => {
tool.action();
};
const changeFixedImage = () => {
canvasEditor.value.changeFixedImage(changeImageUrl, {
imageMode: "contains", // 设置底图包含在画布内
});
};
const canvasInit = () => {
console.log("画布初始化完成");
// 可以在这里执行一些初始化逻辑
// canvasEditor.value.changeFixedImage(clothingImageUrlInit, {
// imageMode: "contains", // 设置底图包含在画布内
// });
};
const frontBackChange = (value) => {};
// 自定义工具配置相关
const customToolsList = ref([
{
id: "exportColorLayer",
title: "导出颜色图层",
action: exportColorLayer,
label: "导颜",
class: "export-btn",
},
{
id: "exportExtraInfo",
title: "导出印花颜色等信息",
action: exportExtraInfo,
label: "导E",
class: "export-btn",
},
{
id: "updateExtraInfo_color",
title: "更新颜色",
action: updateOtherLayersColor,
label: "更C",
class: "export-btn",
},
{
id: "updateExtraInfo_print",
title: "更新印花",
action: updateOtherLayersPrint,
label: "更P",
class: "export-btn",
},
{
id: "exportPNG",
title: "导出PNG", //导出画布图片
action: exportAsPNG,
icon: { name: "CExport", size: "24" },
class: "export-btn",
},
{
id: "saveCanvas",
title: "保存画布",
action: saveCanvas,
icon: { name: "CBottom", size: "24" },
class: "save-btn",
},
{
id: "readCanvas",
title: "读取画布",
action: canvasProject,
icon: { name: "CMiniMap", size: "24" },
class: "clear-btn",
},
{
id: "loadImageUrlToLayer",
title: "添加画布图片",
action: loadImageUrlToLayer,
label: "🎨",
class: "export-btn",
},
{
id: "redGreenExample",
title: "红绿图模式",
action: () => switchView("redGreenExample"),
label: "红",
class: "export-btn",
},
{
id: "canvasEditor",
title: "普通模式",
action: () => switchView("canvasEditor"),
label: "普",
class: "export-btn",
},
{
id: "changeFixedImage",
title: "更换底图",
action: changeFixedImage,
label: "更",
class: "export-btn",
},
{
id: "exportJSON",
title: "导出JSON",
action: exportJSON,
label: "导J",
class: "export-btn",
},
{
id: "copyJSON",
title: "复制JSON",
action: copyJSON,
label: "复J",
class: "export-btn",
},
{
id: "getLayers",
title: "查询图层",
action: getLayers,
label: "查L",
class: "export-btn",
},
]);
2026-01-19 16:57:11 +08:00
const canvasLoadJsonSuccess = () => {
console.log("画布加载JSON成功");
canvasEditor.value?.updateOtherLayers({
color: { rgba: { r: 255, g: 0, b: 0, a: 1 } },
printObject: {
prints: [
{
ifSingle: false,
level2Type: "Pattern",
designType: "Library",
path: "/src/assets/images/canvas/yinhua1.jpg",
location: [250, 780],
scale: [1.2, 1.6],
angle: 0,
object: {
top: 600,
left: 800,
scaleX: 0.5,
scaleY: 0.5,
opacity: 1,
angle: 45,
flipX: false,
flipY: false,
blendMode: "multiply",
gapX: 0,
gapY: 0,
},
2026-01-16 10:29:03 +08:00
},
2026-01-19 16:57:11 +08:00
// {
// ifSingle: true,
// level2Type: "Pattern",
// designType: "Library",
// path: "/src/assets/images/canvas/yinhua1.jpg",
// location: [550, 650],
// scale: [0.15, 0.2],
// angle: 0,
// },
// {
// ifSingle: true,
// level2Type: "Pattern",
// designType: "Library",
// path: "/src/assets/images/canvas/yinhua1.jpg",
// location: [700, 400],
// scale: [0.1, 0.133],
// angle: 0,
// },
],
},
});
2026-01-16 10:29:03 +08:00
};
</script>
<template>
2026-01-16 10:29:03 +08:00
<div class="app-container-example">
<!-- 模拟左侧导航栏 -->
<!-- <div
class="app-wrapper-btns"
:class="{ hide: !isShowLeft }"
@click="isShowLeft = !isShowLeft"
>
<div class="app-btn">收起/展开</div>
2025-08-24 17:11:04 +08:00
</div> -->
2026-01-16 10:29:03 +08:00
<!-- 内容区域 -->
<div class="app-content">
<!-- 红绿图模式示例 -->
<RedGreenModeExample
v-if="currentView === 'redGreenExample'"
key="redGreenExample"
@trigger-red-green-mouseup="frontBackChange"
>
</RedGreenModeExample>
<!-- 普通画布编辑器 -->
<CanvasEditor
ref="canvasEditor"
key="canvasEditor"
v-if="currentView === 'canvasEditor'"
2026-01-16 15:16:33 +08:00
:clothingMinIOPath="clothingMinIOPath"
2026-01-16 10:29:03 +08:00
:clothingImageUrl="clothingImageUrl"
:clothingImageUrl2="clothingImageUrlInit"
:config="editorConfig"
:clothing-image-opts="{
imageMode: 'contains', // 设置底图包含在画布内
}"
@change-canvas="changeCanvas"
@canvas-init="canvasInit"
showFixedLayer
>
<template #existsImageList>
<ExistsImageList
:list="imageData"
@select="handleImageSelect"
/>
</template>
<!-- 使用插槽添加自定义工具栏按钮 -->
<template #customToolsBottom="{ toolButtonProps }">
<!-- 分隔线 -->
<div class="tool-separator"></div>
<!-- 自定义工具按钮 -->
<ToolButton
v-for="tool in customToolsList"
:key="tool.id"
:tool="tool"
:active-tool="toolButtonProps.activeTool"
@click="handleCustomToolClick"
tipBody
/>
</template>
</CanvasEditor>
</div>
</div>
</template>
<style scoped lang="less">
2026-01-16 10:29:03 +08:00
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.canvas-wrapper-btns {
position: fixed;
top: 10px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
display: flex;
gap: 10px;
}
html,
body {
height: 100%;
overflow: hidden;
}
.app-container {
height: 100%;
// height: 100vh;
display: flex;
flex-direction: column;
}
.app-container-example {
height: 100vh;
display: flex;
flex-direction: row;
}
.app-wrapper-btns {
position: relative;
width: 200px;
height: 100vh;
background: #f8f9fa;
z-index: 1000;
transition: all 0.3s ease;
&.app-btn {
cursor: pointer;
}
&.hide {
width: 20px;
}
}
.view-switcher {
display: flex;
gap: 8px;
.switch-btn {
padding: 8px 16px;
border: 1px solid #ddd;
border-radius: 6px;
background: white;
cursor: pointer;
font-size: 14px;
transition: all 0.2s;
&:hover {
border-color: #007bff;
background: #f8f9fa;
}
&.active {
border-color: #007bff;
background: #007bff;
color: white;
}
}
}
.app-header {
position: fixed;
top: 10px;
right: 10px;
z-index: 1000;
background: rgba(255, 255, 255, 0.95);
padding: 8px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
}
.app-content {
position: relative;
flex: 1;
height: 100vh;
}
/* 自定义工具按钮样式 */
.tool-separator {
width: 100%;
height: 1px;
background-color: #e0e0e0;
margin: 8px 0;
}
.custom-tool-btn {
position: relative;
width: 3.5rem;
height: 3.5rem;
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1.6rem;
color: #333;
transition: all 0.2s ease;
}
.custom-tool-btn:hover {
background-color: #f0f0f0;
}
.custom-tool-btn:hover .tool-tooltip {
display: block;
}
.tool-tooltip {
display: none;
pointer-events: none;
position: absolute;
writing-mode: vertical-rl; /* 竖直排列 */
text-orientation: upright; /* 保持文字正常显示 */ // left: 100%;
left: 50%;
top: -0.8rem;
transform: translate(-50%, -100%);
background-color: rgba(0, 0, 0, 0.9);
color: white;
padding: 0.8rem 0.4rem;
border-radius: 0.4rem;
white-space: nowrap;
font-size: 1.2rem;
z-index: 10;
}
.tool-tooltip:before {
content: "";
position: absolute;
left: 50%;
bottom: 0;
transform: translate(-50%, 100%);
border-width: 0.5rem;
border-style: solid;
border-color: rgba(0, 0, 0, 0.9) transparent transparent transparent;
}
/* 深色模式适配 */
@media (prefers-color-scheme: dark) {
.app-header {
background: rgba(45, 45, 45, 0.95);
.view-switcher .switch-btn {
background: #3d3d3d;
border-color: #555;
color: #e0e0e0;
&:hover {
border-color: #007bff;
background: #444;
}
&.active {
background: #007bff;
color: white;
}
}
}
}
</style>