添加衣服纹理功能

This commit is contained in:
X1627315083
2024-03-20 13:34:07 +08:00
parent 5f9fe870c7
commit c5e3a5036d
33 changed files with 579 additions and 129 deletions

View File

@@ -13,7 +13,7 @@
<i class="fi fi-rr-cross-small" @click.stop="cancelDsign()"></i>
</div>
<div class="UpgradePlan_content">
<div>Export</div>
<div>Edit & Export</div>
</div>
<!-- <div>
<canvas ref="exportCanvas"></canvas>
@@ -83,11 +83,13 @@
<i class="icon iconfont icon-chehui" @click="historyState('')"></i>
<i class="icon iconfont icon-fanchehui" @click="historyState('reverse')"></i>
<i class="icon iconfont icon-bianji" @click="setOperation('pencil')" :class="{active:operation == 'pencil'}"></i>
<i class="icon iconfont icon-caizhi" @click="setOperation('texture')" :class="{active:operation == 'texture'}"></i>
<i class="icon iconfont icon-move" @click="setOperation('move')" :class="{active:operation == 'move'}"></i>
<i class="icon iconfont icon-xiangpi_huaban1" @click="setOperation('eraser')" :class="{active:operation == 'eraser'}"></i>
</div>
<div class="exportCanvasBox_left_tool_item">
<label v-show="operation != 'move' && operation != 'eraser'">
<label v-show="operation != 'move' && operation != 'eraser' && operation != 'texture'">
<div >Color</div>
<input type="color" @input="setPencilColor" v-model="canvasPencilColor">
</label>
@@ -97,11 +99,7 @@
</label>
<label v-show="operation == 'pencil'">
<div >Brushwork:</div>
<a-select
ref="select"
class="label_select"
size="small"
v-model:value="brushworkValue"
<a-select ref="select" class="label_select" size="small" v-model:value="brushworkValue"
style="flex: 1"
@change="brushworkChange"
>
@@ -109,16 +107,36 @@
<a-select-option class="label_select_item" v-for="item in brushList" :value="item.value">
<img :src="item.url" alt="">
</a-select-option>
<!-- <a-select-option value="Marking">Marking</a-select-option>
<a-select-option value="InkBrush">InkBrush</a-select-option>
<a-select-option value="CrayonBrush">CrayonBrush</a-select-option>
<a-select-option value="RibbonBrush">RibbonBrush</a-select-option>
<a-select-option value="MarkerBrush">MarkerBrush</a-select-option>
<a-select-option value="WritingBrush">WritingBrush</a-select-option>
<a-select-option value="LongfurBrush">LongfurBrush</a-select-option>
<a-select-option value="SpraypaintBrush">SpraypaintBrush</a-select-option> -->
</a-select>
</label>
<label v-show="operation == 'texture'" class="texture">
<div >Texture:</div>
<a-select ref="select" class="label_select" size="small" v-model:value="textureValue"
style="flex: 1"
@change="textureValueChange"
>
<!-- v-model:value="brushwork" -->
<a-select-option class="label_select_item" v-for="item in textureList" :value="item.value">
<img :src="item.url" alt="">
</a-select-option>
</a-select>
</label>
<label v-show="operation != 'pencil' && operation != 'eraser'&&operation != 'move'&&operation != 'texture'">
<div >FillBack:</div>
<div class="exportCanvasBox_left_tool_item leftAlign">
<i class="icon iconfont icon-tuceng1" @click="setOperationMode('fill')" :class="{active:operationMode == 'fill'}"></i>
<i class="icon iconfont icon-tuceng" @click="setOperationMode('border')" :class="{active:operationMode == 'border'}"></i>
</div>
</label>
<label v-show="operation === 'move'">
<div >Layer:</div>
<div class="exportCanvasBox_left_tool_item">
<i class="icon iconfont icon-shangyiceng" @click="setLayerIndex('Front')"></i>
<i class="icon iconfont icon-shangyiceng2" @click="setLayerIndex('Forward')"></i>
<i class="icon iconfont icon-xiayiceng" @click="setLayerIndex('Backwards')"></i>
<i class="icon iconfont icon-shangyiceng1" @click="setLayerIndex('Back')"></i>
</div>
</label>
</div>
</div>
<div class="exportCanvasBox_title" @click.stop="setCloseNav('move')">
@@ -135,17 +153,14 @@
</div>
<div class="exportCanvasBox_left_tool exportCanvasBox_left_item" :class="{'closeNav' :closeNav.move}">
<div class="exportCanvasBox_left_tool_item">
<i class="icon iconfont icon-xian" @click="setOperation('fold')" :class="{active:operation == 'fold'}"></i>
<i class="icon iconfont icon-checkbox-full" @click="setOperation('rect')" :class="{active:operation == 'rect'}"></i>
<i class="icon iconfont icon-zhixian" @click="setOperation('line')" :class="{active:operation == 'line'}"></i>
<i class="icon iconfont icon-circle" @click="setOperation('circle')" :class="{active:operation == 'circle'}"></i>
<!-- <i class="icon iconfont icon-zhixian" @click="setOperation('line')" :class="{active:operation == 'line'}"></i> -->
<!-- <i class="icon iconfont icon-circle" @click="setOperation('circle')" :class="{active:operation == 'circle'}"></i> -->
<i class="icon iconfont icon-sanjiaoxing" @click="setOperation('triangle')" :class="{active:operation == 'triangle'}"></i>
<i class="icon iconfont icon-tx-fill-tuoyuanxing" @click="setOperation('ellipse')" :class="{active:operation == 'ellipse'}"></i>
<i class="icon iconfont icon-xian" @click="setOperation('fold')" :class="{active:operation == 'fold'}"></i>
</div>
<div class="exportCanvasBox_left_tool_item leftAlign">
<i class="icon iconfont icon-tuceng1" @click="setOperationMode('fill')" :class="{active:operationMode == 'fill'}"></i>
<i class="icon iconfont icon-tuceng" @click="setOperationMode('border')" :class="{active:operationMode == 'border'}"></i>
</div>
</div>
</div>
<div class="exportCanvasBox_center">
@@ -191,7 +206,7 @@ import { useStore } from "vuex";
import JSZip, { forEach } from "jszip";
import { message, Modal } from "ant-design-vue";
const FileSaver = require("file-saver");
import { exportSele,JSRectUpdata,JSchangeType,JScanvasMouseDown,JScanvasMouseMove,JScreateCheck } from "@/tool/canvasDrawing";
import { exportSele,JSRectUpdata,JSchangeType,JScanvasMouseDown,JScanvasMouseMove,JScreateCheck,JSSetTexture } from "@/tool/canvasDrawing";
export default defineComponent({
components: {
scaleImage,
@@ -252,12 +267,9 @@ export default defineComponent({
canvasBox.appendChild(canvasDom);
canvas = new fabric.Canvas(canvasDom, {
backgroundColor: "rgba(255, 255, 255)",
// fill: '#ffde7d',
// selection: false, //设置多选
width: canvasWH.value.width,
height: canvasWH.value.height,
isDrawingMode: false, // 开启绘图模式
// preserveObjectStacking: true,
});
JSchangeType(canvas,'init')
canvasOnDrop()//开启鼠标到画布事件
@@ -265,6 +277,7 @@ export default defineComponent({
canvas.on("object:modified", ()=>{
updateCanvasState()
});
canvas.preserveObjectStacking = true;
//鼠标移动
canvas.on("mouse:move", event =>setCanvasMove(event));
canvas.on("mouse:out", event=>setCanvasOut(event));
@@ -293,6 +306,8 @@ export default defineComponent({
let oldKey = "";
let margin = 20; //每个图形边距
let maxHeight = 0
let sketchXy = {x:0,y:0}
// arr.forEach((item,index)=>{
for (const item of arr) {
for (const key in allBoardData.value) {
@@ -308,11 +323,12 @@ export default defineComponent({
}
for (const [allItemIndex, allItem,] of allBoardData.value[key].entries()) {
await new Promise((resolve, reject) => {
maxHeight = position.y + position.height>maxHeight?position.y +position.height:maxHeight
if (key == "colorBoards") {
let rect = setGroup(allItem)
if (position.x + rect.width > canvasWH.value.width || oldKey != key) {
position.x = 0;
position.y += position.height;
position.y = maxHeight;
}
let group = setCanvasColor(position.y,position.x,rect)
oldKey = key;
@@ -327,55 +343,62 @@ export default defineComponent({
}
fabric.Image.fromURL(itemCanvasImg,(img) => {
let scaleWH = imgWidth / img.width; //计算放到画布上缩小倍率
if (position.x + img.width * scaleWH > canvasWH.value.width || oldKey != key) {
position.x = 0;
position.y += position.height;
if(key == "sketchboardFiles"){
if(allItemIndex == 0){
position.x = 0;
position.y = maxHeight;
}
}else{
if (position.x + img.width * scaleWH > canvasWH.value.width || oldKey != key) {
position.x = 0;
position.y = maxHeight;
}
}
setCanvasImage(img,key,position.x,position.y)//设置图片
position.height = img.height * scaleWH + margin;
if (key == "sketchboardFiles") {
position.x +=
img.width * scaleWH +
margin;
if (sketchGroupingItem.length >= 3) {
} else {
if (sketchGroupingItem.length <3) {
sketchGroupingItem.push(JSON.parse(JSON.stringify(position)));
}
if (sketchGroupingItem.length >=3) {
if (sketchGroupingItem.length >2) {
let sketchXyIndex = {
maxIndex: 0,
maxNum: 9999999999,
minNum: 0,
maxNum: 0,
minNum: 999999,
minIndex: 0,
};
sketchGroupingItem.forEach(
(sketchItem,sketchIndex) => {
if (sketchItem.height <sketchXyIndex.maxNum) {
sketchXyIndex.maxNum = sketchItem.height;
sketchXyIndex.maxIndex = sketchIndex;
}
if (sketchItem.height > sketchXyIndex.minNum) {
sketchXyIndex.minNum = sketchItem.height;
if (sketchItem.y + sketchItem.height < sketchXyIndex.minNum) {
// console.log(sketchItem.x,sketchItem.y);
sketchXyIndex.minNum = sketchItem.y + sketchItem.height
sketchXyIndex.minIndex = sketchIndex;
}
if (sketchItem.y + sketchItem.height > sketchXyIndex.maxNum) {
sketchXyIndex.maxNum = sketchItem.y + sketchItem.height
sketchXyIndex.maxIndex = sketchIndex;
}
}
);
sketchGroupingItem[sketchXyIndex.minIndex].y = sketchXyIndex.minNum
// sketchGroupingItem[sketchXyIndex.maxIndex].y = sketchXyIndex.maxNum
if (allBoardData.value[key].length == allItemIndex + 1) {
position = sketchGroupingItem[sketchXyIndex.minIndex];
maxHeight = sketchXyIndex.maxNum
} else {
position = sketchGroupingItem[ sketchXyIndex.maxIndex];
position.y += position.height;
position.x -= img.width * scaleWH + margin;
position = sketchGroupingItem[sketchXyIndex.minIndex];
}
}
} else {
position.x += img.width * scaleWH;
}
if(key == "sketchboardFiles" && sketchGroupingItem.length >2){
}else{
position.x += img.width * scaleWH + margin;
}
img.lock_rotation = true;
canvas.add(img);
oldKey = key;
resolve();
// setTimeout(() => {
resolve()
// }, 1000);
},{ crossOrigin: "Anonymous" });
}
});
@@ -390,10 +413,13 @@ export default defineComponent({
updateCanvasState('')//加载完成后记录一下
});
};
let setRemoveImage = ()=>{
let deleteObject = (eventData, transform)=> {
let deleteObject = (eventData, transform)=> {
// var target = [transform.target];
let target = canvas.getActiveObjects()
if(!target){
return
}
target.forEach((item)=>{
// var canvas = item.canvas;
// canvas.remove(item);
@@ -411,6 +437,8 @@ export default defineComponent({
// canvas.renderAll(); // 重新渲染 Canvas
updateCanvasState('remove')
}
let setRemoveImage = ()=>{
const deleteIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAACxAAAAsQHGLUmNAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAAdBJREFUSImt1r1uU0EQBeDPFh1pgBQEEwFVAg9BROhCAh1FAg1gkMA8DA0oKOEB3IEIRQgF4SEQBIUC6ENSGgPFXaPx+udeSxxppPXOzJnZ8e7MrRmPWdzANZxPv+EbvmILL/G9hGcADayjgz8l0kUb56qSX8dhBeJcDrFSRv44ZRQdt3EPczieZB5NvB1ymta4zCP5J1yucOIFfM6CDJykob8s73GiAnkPJ7Eb/H9iJhpsZJlPQh6D7AWe9Z5iFr+CIpalhjWspnXZ/pXA01FURkv/HxpxK+g2UE+yGfZXM5+doHt4DEtB2R5dAXdD9nfG2LVxNa2XKGreiziXGefZ5rKZbCLmg/4jHIWNqSEZ1fC0IrnE0bM5qqdFGWoV92RBf/P/S3RRVqI3YaOZGd8eQpgHXMt8HgTd67qi5fZwMzOO5XuREmim9ShEji04q78tLwSDSR/aYuD599DgeVDsY3pMhqOQt4pnUXlGf7PbTQ5VcQofgv8BTudGK/rb9Z6it5RhEV+CX1cxYoeiZXDg7OC+4vpNJbmkuC3vMtsuHpVltKzo55OOzINxmeeYxhPVhn5H0ftnhhGNeu49NBSjdBkX9H+27Cvu+Sv8GEXwF9+O3b1zwZqdAAAAAElFTkSuQmCC"
// 创建删除图片元素
let deleteImg = document.createElement('img')
@@ -509,11 +537,7 @@ export default defineComponent({
break;
}
let nameTail = item?.imgUrl
?.split(".")
.pop()
.split("?")
.shift();
let nameTail = item?.imgUrl?.split(".").pop().split("?").shift();
let data = {
imgUrl: item.imgUrl,
@@ -521,7 +545,7 @@ export default defineComponent({
};
if (key == "likeDesignCollectionList") {
data.imgUrl = item.designOutfitUrl;
data.name = "result" + index + "." + nameTail;
data.name = "result" + index + "." + data.imgUrl.split(".").pop().split("?").shift();;
}
img.push(data);
index++;
@@ -747,8 +771,6 @@ export default defineComponent({
// reverseCanvasState.value.push(canvasAsJson);
}
normalCanvasState.value.push(canvasAsJson);
console.log(normalCanvasState.value);
if (isLoadCanvas) {
reverseCanvasState.value = []
isLoadCanvas = false;
@@ -775,6 +797,12 @@ export default defineComponent({
//在画布进行画画
let operation = ref('move')
let operationMode = ref('fill')
let textureValue = ref(0)//材质信息
let textureValueChange = (value)=>{
textureValue.value = value
setTexture()
}
//铅笔颜色 大小
let brushworkValue = ref('PencilBrush')
let brushworkChange = (value)=>{
@@ -783,7 +811,35 @@ export default defineComponent({
}
// let brushwork = ref('')
// 监听键盘的 keydown 和 keyup 事件
let keyDown = []
document.addEventListener('keydown', function(event) {
if(keyDown.indexOf(event.key)>-1){
}else{
keyDown.push(event.code)
if(event.key === 'Enter' && operation.value == 'fold'){
foldEnd('Enter')
}else if(event.key === 'Delete'){
deleteObject()
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyZ') > -1 && keyDown.indexOf('ShiftLeft') > -1){
historyState('reverse')
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyZ') > -1){
historyState('')
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyC') > -1){
copy()
}else if(keyDown.indexOf('ControlLeft') > -1 && keyDown.indexOf('KeyV') > -1){
paste()
}
}
});
document.addEventListener('keyup', function(event) {
keyDown = keyDown.filter(function(item) {
return event.code !== item;
});
});
let canvasPencilColor = ref('#000000')
let canvasPencilWidth = ref(20)
let setOperation = (str)=>{
@@ -801,6 +857,8 @@ export default defineComponent({
setMove()
canvas.forEachObject((obj) =>obj.selectable = true);
JSchangeType(canvas,'init')
}else if(str == 'texture'){
setTexture()
}else if(str == 'eraser'){
setEraser()
}else{
@@ -808,9 +866,82 @@ export default defineComponent({
canvas.isDrawingMode = false
}
}
let _clipboard = null // 复制到的内容
let copy = () => {//复制
var activeObject = canvas.getActiveObject();
if(!activeObject){
return
}
activeObject.clone(function(cloned) {
_clipboard = cloned;
})
}
let paste = () => {//粘贴
if(!_clipboard){
return
}
_clipboard.clone(clonedObj => {
canvas.discardActiveObject() // 取消选择
// 设置新内容的坐标位置
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true
})
if (clonedObj.type === 'activeSelection') {
// 活动选择需要一个对画布的引用
clonedObj.canvas = canvas;
clonedObj.forEachObject(function(obj) {
canvas.add(obj)
})
clonedObj.setCoords()
} else {
canvas.add(clonedObj)
}
_clipboard.top += 10
_clipboard.left += 10
canvas.setActiveObject(clonedObj)
canvas.requestRenderAll()
})
updateCanvasState()
}
let textureList = ref([])
for (let index = 0; index < 20; index++) {
textureList.value.push({value:index,url:`./image/texture/texture${index}.webp`})
}
let setTexture = async ()=>{
canvas.isDrawingMode = true//开启绘画模式
let img = await JSSetTexture(textureList.value[textureValue.value].url)
let patternBrush = new fabric.PatternBrush(canvas)
patternBrush.source = img
patternBrush.width = canvasPencilWidth.value; // 设置画笔大小
canvas.freeDrawingBrush = patternBrush
}
let setOperationMode = (str) =>{
operationMode.value = str
}
let setLayerIndex = (str) =>{//设置优先级
var activeObject = canvas.getActiveObject();
switch (str) {
case 'Front':
canvas.bringToFront(activeObject)//顶层
break
case 'Back':
canvas.sendToBack(activeObject)//底层
break
case 'Forward':
canvas.bringForward(activeObject)
break
case 'Backwards':
canvas.sendBackwards(activeObject)
break
}
}
let brushIndicator = new fabric.Circle({
radius:canvasPencilWidth.value/2,
fill: '#fff',
@@ -859,7 +990,6 @@ export default defineComponent({
])
let setPencil =()=>{
let pencil
canvas.preserveObjectStacking = true;
canvas.isDrawingMode = true//开启绘画模式
if(brushworkValue.value == 'PencilBrush'){
pencil = new fabric.PencilBrush(canvas,{}); //普通笔
@@ -873,6 +1003,7 @@ export default defineComponent({
pencil = new fabric.RibbonBrush(canvas,{width: 1,}); //色带
}else if(brushworkValue.value == 'MarkerBrush'){
pencil = new fabric.MarkerBrush(canvas,{}); //书写笔
// pencil = new fabric.PenBrush(canvas,{}); //书写笔
}else if(brushworkValue.value == 'WritingBrush'){
pencil = new fabric.WritingBrush(canvas,{}); //毛笔
}else if(brushworkValue.value == 'LongfurBrush'){
@@ -889,8 +1020,8 @@ export default defineComponent({
}
if(brushworkValue.value == 'Marking'){
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,.5);
}else if(brushworkValue.value == 'InkBrush'){
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,.2);
// }else if(brushworkValue.value == 'InkBrush'){
// canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,.2);
}else{
canvas.freeDrawingBrush.color = hexToRgba(canvasPencilColor.value,1);
}
@@ -977,7 +1108,7 @@ export default defineComponent({
}else{
if(createPatterningIs){
JScanvasMouseMove(operation.value,event,currentPatterning,downPoint)
JScanvasMouseMove(operation.value,event,currentPatterning,downPoint,keyDown)
}
}
canvas.requestRenderAll()
@@ -1001,35 +1132,39 @@ export default defineComponent({
})
// currentPatterning = JScanvasMouseDown(operation.value,event,canvasPencilWidth.value,currentPatterning)
}else{
if(operation.value == 'fold'){
polyLineBtn = JScreateCheck(event)
polyLineBtn.on('mousedown',()=>{
canvas.skipTargetFind = true
let points = currentPatterning.points
points.pop()
points.pop()
canvas.remove(currentPatterning)
let polyline = new fabric.Polyline(points, {
fill: 'transparent',
stroke: canvasPencilColor.value,
strokeWidth:canvasPencilWidth.value,
selection:false,
})
canvas.add(polyline)
// currentPatterning.set({stroke: canvasPencilColor.value})
createPatterningIs = false
clearPatterning()//临时图形置为空并且添加撤回对象里面
})
canvas.add(polyLineBtn)
}
currentPatterning = JScanvasMouseDown(operation.value,event,canvasPencilWidth.value,currentPatterning)
canvas.add(currentPatterning)
canvas.bringToFront(currentPatterning);//设置优先级最高
if(operation.value == 'fold'){
polyLineBtn = JScreateCheck(event)
polyLineBtn.on('mousedown',foldEnd)
canvas.add(polyLineBtn)
}
}
}else{
createPatterningIs = false
}
}
let foldEnd = (key)=>{
canvas.skipTargetFind = true
let points = currentPatterning.points
if(key == 'Enter'){
}else{
points.pop()
}
points.pop()
canvas.remove(currentPatterning)
let polyline = new fabric.Polyline(points, {
fill: operationMode.value == 'fill'? canvasPencilColor.value : 'transparent',
stroke: canvasPencilColor.value,
strokeWidth:canvasPencilWidth.value,
selection:false,
})
canvas.add(polyline)
// currentPatterning.set({stroke: canvasPencilColor.value})
createPatterningIs = false
clearPatterning()//临时图形置为空并且添加撤回对象里面
}
//设置再画布上抬起
let setCanvasUp = (event)=>{
upPoint = event.absolutePointer
@@ -1071,8 +1206,12 @@ export default defineComponent({
}
let setHDExport = async ()=>{//获取选中内容的位置信息
let imgData = await exportSele(canvas,'jpg')
let img = new Image
img.src = imgData
img.onload = ()=>{
console.log(img.width,img.height);
}
console.log(imgData);
}
onMounted(() => {});
@@ -1095,14 +1234,18 @@ export default defineComponent({
operationMode,//设置矩形是边框还是填充
setOperation,//设置当前鼠标状态绘画或者矩形或者移动方法
setOperationMode,//设置矩形是边框还是填充方法
setLayerIndex,//设置选中元素的层级
brushList,//笔触列表
textureList,//材质列表
canvasPencilColor,//input选择颜色
canvasPencilWidth,//input选择宽度
setPencilColor,//切换颜色执行函数 给当前矩形或者笔触设置颜色
setPencilWidth,//切换宽度执行函数 给当前矩形或者笔触设置宽度
setHDExport,//高清导出选择的图片
brushworkChange,//切换笔触的回调
textureValueChange,//切换材质信息
brushworkValue,//当前笔触
textureValue,//当前材质
};
},
data(prop) {
@@ -1202,7 +1345,6 @@ export default defineComponent({
height: 100%;
overflow-x: hidden;
label {
cursor: pointer;
display: flex;
align-items: center;
margin-bottom: 1rem;
@@ -1223,6 +1365,13 @@ export default defineComponent({
}
}
}
.texture{
.label_select{
img{
max-height: none;
}
}
}
.exportCanvasBox_left_item.closeNav{
// max-height: 1000rem;
height: auto;
@@ -1283,6 +1432,7 @@ export default defineComponent({
.exportCanvasBox_left_tool{
.exportCanvasBox_left_tool_item{
display: flex;
flex: 1;
flex-wrap: wrap;
justify-content: space-between;
margin-bottom: 1rem;