Files
aida_front/src/component/Canvas/canvasExample.vue
李志鹏 618b9bab1f fix
2026-01-16 15:16:33 +08:00

625 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
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
const clothingMinIOPath =
"aida-users/24299/sketchboard/female/Outwear/32d2485c-90fa-43d0-bc31-e59aaea466ba.png";
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",
},
]);
const otherData = {
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,
},
},
// {
// 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,
// },
],
},
};
</script>
<template>
<div class="app-container-example">
<!-- 模拟左侧导航栏 -->
<!-- <div
class="app-wrapper-btns"
:class="{ hide: !isShowLeft }"
@click="isShowLeft = !isShowLeft"
>
<div class="app-btn">收起/展开</div>
</div> -->
<!-- 内容区域 -->
<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'"
:clothingMinIOPath="clothingMinIOPath"
:clothingImageUrl="clothingImageUrl"
:clothingImageUrl2="clothingImageUrlInit"
:otherData="otherData"
:config="editorConfig"
:clothing-image-opts="{
imageMode: 'contains', // 设置底图包含在画布内
}"
@change-canvas="changeCanvas"
@canvas-init="canvasInit"
isFixedErasable
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">
* {
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>