Merge branch 'dev_vite' of ssh://18.167.251.121:10002/aidlab/aida_front into dev_vite
260
package-lock.json
generated
@@ -34,6 +34,7 @@
|
|||||||
"vue-draggable-plus": "^0.6.0",
|
"vue-draggable-plus": "^0.6.0",
|
||||||
"vue-i18n": "^9.6.1",
|
"vue-i18n": "^9.6.1",
|
||||||
"vue-router": "^4.0.3",
|
"vue-router": "^4.0.3",
|
||||||
|
"vue3-moveable": "^0.28.0",
|
||||||
"vuedraggable": "^4.1.0",
|
"vuedraggable": "^4.1.0",
|
||||||
"vuex": "^4.0.0",
|
"vuex": "^4.0.0",
|
||||||
"x-sender": "^1.1.6"
|
"x-sender": "^1.1.6"
|
||||||
@@ -232,6 +233,15 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@cfcs/core": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@cfcs/core/-/core-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-FxfJMwoLB8MEMConeXUCqtMGqxdtePQxRBOiGip9ULcYYam3WfCgoY6xdnMaSkYvRvmosp5iuG+TiPofm65+Pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@egjs/component": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ctrl/tinycolor": {
|
"node_modules/@ctrl/tinycolor": {
|
||||||
"version": "3.6.1",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
|
||||||
@@ -240,6 +250,39 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@daybrush/utils": {
|
||||||
|
"version": "1.13.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@daybrush/utils/-/utils-1.13.0.tgz",
|
||||||
|
"integrity": "sha512-ALK12C6SQNNHw1enXK+UO8bdyQ+jaWNQ1Af7Z3FNxeAwjYhQT7do+TRE4RASAJ3ObaS2+TJ7TXR3oz2Gzbw0PQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@egjs/agent": {
|
||||||
|
"version": "2.4.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@egjs/agent/-/agent-2.4.4.tgz",
|
||||||
|
"integrity": "sha512-cvAPSlUILhBBOakn2krdPnOGv5hAZq92f1YHxYcfu0p7uarix2C6Ia3AVizpS1SGRZGiEkIS5E+IVTLg1I2Iog==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@egjs/children-differ": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@egjs/children-differ/-/children-differ-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-DRvyqMf+CPCOzAopQKHtW+X8iN6Hy6SFol+/7zCUiE5y4P/OB8JP8FtU4NxtZwtafvSL4faD5KoQYPj3JHzPFQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@egjs/list-differ": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@egjs/component": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@egjs/component/-/component-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-cLcGizTrrUNA2EYE3MBmEDt2tQv1joVP1Q3oDisZ5nw0MZDx2kcgEXM+/kZpfa/PAkFvYVhRUZwytIQWoN3V/w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@egjs/list-differ": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@egjs/list-differ/-/list-differ-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-OTFTDQcWS+1ZREOdCWuk5hCBgYO4OsD30lXcOCyVOAjXMhgL5rBRDnt/otb6Nz8CzU0L/igdcaQBDLWc4t9gvg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@element-plus/icons-vue": {
|
"node_modules/@element-plus/icons-vue": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz",
|
||||||
@@ -1224,6 +1267,34 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@scena/dragscroll": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@scena/dragscroll/-/dragscroll-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-3O8daaZD9VXA9CP3dra6xcgt/qrm0mg0xJCwiX6druCteQ9FFsXffkF8PrqxY4Z4VJ58fFKEa0RlKqbsi/XnRA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.6.0",
|
||||||
|
"@scena/event-emitter": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@scena/event-emitter": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@scena/event-emitter/-/event-emitter-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-AzY4OTb0+7ynefmWFQ6hxDdk0CySAq/D4efljfhtRHCOP7MBF9zUfhKG3TJiroVjASqVgkRJFdenS8ArZo6Olg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@scena/matrix": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@scena/matrix/-/matrix-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-JVKBhN0tm2Srl+Yt+Ywqu0oLgLcdemDQlD1OxmN9jaCTwaFPZ7tY8n6dhVgMEaR9qcR7r+kAlMXnSfNyYdE+Vg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@simonwep/pickr": {
|
"node_modules/@simonwep/pickr": {
|
||||||
"version": "1.8.2",
|
"version": "1.8.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@simonwep/pickr/-/pickr-1.8.2.tgz",
|
"resolved": "https://registry.npmmirror.com/@simonwep/pickr/-/pickr-1.8.2.tgz",
|
||||||
@@ -2904,6 +2975,52 @@
|
|||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/croact": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/croact/-/croact-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-9GhvyzTY/IVUrMQ2iz/mzgZ8+NcjczmIo/t4FkC1CU0CEcau6v6VsEih4jkTa4ZmRgYTF0qXEZLObCzdDFplpw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"@egjs/list-differ": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/croact-css-styled": {
|
||||||
|
"version": "1.1.9",
|
||||||
|
"resolved": "https://registry.npmmirror.com/croact-css-styled/-/croact-css-styled-1.1.9.tgz",
|
||||||
|
"integrity": "sha512-G7yvRiVJ3Eoj0ov2h2xR4312hpOzATay2dGS9clK8yJQothjH1sBXIyvOeRP5wBKD9mPcKcoUXPCPsl0tQog4w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"css-styled": "~1.0.8",
|
||||||
|
"framework-utils": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/croact-moveable": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/croact-moveable/-/croact-moveable-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-fc3bieV6CdqqZFtzsSLi9KmvUMFW3oakUfhPCls1BxKjOfUfn8rktteGED2341A/Qghy8tI3Hm6SdocIc68IKg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"@egjs/agent": "^2.2.1",
|
||||||
|
"@egjs/children-differ": "^1.0.1",
|
||||||
|
"@egjs/list-differ": "^1.0.0",
|
||||||
|
"@scena/dragscroll": "^1.4.0",
|
||||||
|
"@scena/event-emitter": "^1.0.5",
|
||||||
|
"@scena/matrix": "^1.1.1",
|
||||||
|
"croact-css-styled": "^1.1.9",
|
||||||
|
"css-to-mat": "^1.1.1",
|
||||||
|
"framework-utils": "^1.1.0",
|
||||||
|
"gesto": "^1.19.3",
|
||||||
|
"overlap-area": "^1.1.0",
|
||||||
|
"react-css-styled": "^1.1.9",
|
||||||
|
"react-moveable": "~0.56.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"croact": "^1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@@ -3014,6 +3131,25 @@
|
|||||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-styled": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmmirror.com/css-styled/-/css-styled-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-tCpP7kLRI8dI95rCh3Syl7I+v7PP+2JYOzWkl0bUEoSbJM+u8ITbutjlQVf0NC2/g4ULROJPi16sfwDIO8/84g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/css-to-mat": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/css-to-mat/-/css-to-mat-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-kvpxFYZb27jRd2vium35G7q5XZ2WJ9rWjDUMNT36M3Hc41qCrLXFM5iEKMGXcrPsKfXEN+8l/riB4QzwwwiEyQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"@scena/matrix": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/css-tree": {
|
"node_modules/css-tree": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-1.1.3.tgz",
|
"resolved": "https://registry.npmmirror.com/css-tree/-/css-tree-1.1.3.tgz",
|
||||||
@@ -4354,6 +4490,12 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/framework-utils": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/framework-utils/-/framework-utils-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-KAfqli5PwpFJ8o3psRNs8svpMGyCSAe8nmGcjQ0zZBWN2H6dZDnq+ABp3N3hdUmFeMrLtjOCTXD4yplUJIWceg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fs-extra": {
|
"node_modules/fs-extra": {
|
||||||
"version": "10.1.0",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||||
@@ -4485,6 +4627,16 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/gesto": {
|
||||||
|
"version": "1.19.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/gesto/-/gesto-1.19.4.tgz",
|
||||||
|
"integrity": "sha512-hfr/0dWwh0Bnbb88s3QVJd1ZRJeOWcgHPPwmiH6NnafDYvhTsxg+SLYu+q/oPNh9JS3V+nlr6fNs8kvPAtcRDQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"@scena/event-emitter": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
"resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
@@ -5695,6 +5847,24 @@
|
|||||||
"setimmediate": "^1.0.5"
|
"setimmediate": "^1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/keycode": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/keycode/-/keycode-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/keycon": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/keycon/-/keycon-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-p1NAIxiRMH3jYfTeXRs2uWbVJ1WpEjpi8ktzUyBJsX7/wn2qu2VRXktneBLNtKNxJmlUYxRi9gOJt1DuthXR7A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@cfcs/core": "^0.0.6",
|
||||||
|
"@daybrush/utils": "^1.7.1",
|
||||||
|
"@scena/event-emitter": "^1.0.2",
|
||||||
|
"keycode": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz",
|
||||||
@@ -6212,6 +6382,19 @@
|
|||||||
"pathe": "^2.0.1"
|
"pathe": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/moveable": {
|
||||||
|
"version": "0.53.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/moveable/-/moveable-0.53.0.tgz",
|
||||||
|
"integrity": "sha512-71jS9zIoQzMhnNvduhg4tUEdm23+fO/40FN7muVMbZvVwbTku2MIxxLhnU4qFvxI4oVxn75l79SbtgjuA+s7Pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"@scena/event-emitter": "^1.0.5",
|
||||||
|
"croact": "^1.0.4",
|
||||||
|
"croact-moveable": "~0.9.0",
|
||||||
|
"react-moveable": "~0.56.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
|
||||||
@@ -6650,6 +6833,15 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/overlap-area": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/overlap-area/-/overlap-area-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-3dlJgJCaVeXH0/eZjYVJvQiLVVrPO4U1ZGqlATtx6QGO3b5eNM6+JgUKa7oStBTdYuGTk7gVoABCW6Tp+dhRdw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.7.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/own-keys": {
|
"node_modules/own-keys": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/own-keys/-/own-keys-1.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/own-keys/-/own-keys-1.0.1.tgz",
|
||||||
@@ -7037,6 +7229,46 @@
|
|||||||
"safe-buffer": "^5.1.0"
|
"safe-buffer": "^5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-css-styled": {
|
||||||
|
"version": "1.1.9",
|
||||||
|
"resolved": "https://registry.npmmirror.com/react-css-styled/-/react-css-styled-1.1.9.tgz",
|
||||||
|
"integrity": "sha512-M7fJZ3IWFaIHcZEkoFOnkjdiUFmwd8d+gTh2bpqMOcnxy/0Gsykw4dsL4QBiKsxcGow6tETUa4NAUcmJF+/nfw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"css-styled": "~1.0.8",
|
||||||
|
"framework-utils": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-moveable": {
|
||||||
|
"version": "0.56.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/react-moveable/-/react-moveable-0.56.0.tgz",
|
||||||
|
"integrity": "sha512-FmJNmIOsOA36mdxbrc/huiE4wuXSRlmon/o+/OrfNhSiYYYL0AV5oObtPluEhb2Yr/7EfYWBHTxF5aWAvjg1SA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"@egjs/agent": "^2.2.1",
|
||||||
|
"@egjs/children-differ": "^1.0.1",
|
||||||
|
"@egjs/list-differ": "^1.0.0",
|
||||||
|
"@scena/dragscroll": "^1.4.0",
|
||||||
|
"@scena/event-emitter": "^1.0.5",
|
||||||
|
"@scena/matrix": "^1.1.1",
|
||||||
|
"css-to-mat": "^1.1.1",
|
||||||
|
"framework-utils": "^1.1.0",
|
||||||
|
"gesto": "^1.19.3",
|
||||||
|
"overlap-area": "^1.1.0",
|
||||||
|
"react-css-styled": "^1.1.9",
|
||||||
|
"react-selecto": "^1.25.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-selecto": {
|
||||||
|
"version": "1.26.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/react-selecto/-/react-selecto-1.26.3.tgz",
|
||||||
|
"integrity": "sha512-Ubik7kWSnZyQEBNro+1k38hZaI1tJarE+5aD/qsqCOA1uUBSjgKVBy3EWRzGIbdmVex7DcxznFZLec/6KZNvwQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"selecto": "~1.26.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/readable-stream": {
|
"node_modules/readable-stream": {
|
||||||
"version": "2.3.8",
|
"version": "2.3.8",
|
||||||
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
|
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
@@ -7507,6 +7739,24 @@
|
|||||||
"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
|
"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/selecto": {
|
||||||
|
"version": "1.26.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/selecto/-/selecto-1.26.3.tgz",
|
||||||
|
"integrity": "sha512-gZHgqMy5uyB6/2YDjv3Qqaf7bd2hTDOpPdxXlrez4R3/L0GiEWDCFaUfrflomgqdb3SxHF2IXY0Jw0EamZi7cw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@daybrush/utils": "^1.13.0",
|
||||||
|
"@egjs/children-differ": "^1.0.1",
|
||||||
|
"@scena/dragscroll": "^1.4.0",
|
||||||
|
"@scena/event-emitter": "^1.0.5",
|
||||||
|
"css-styled": "^1.0.8",
|
||||||
|
"css-to-mat": "^1.1.1",
|
||||||
|
"framework-utils": "^1.1.0",
|
||||||
|
"gesto": "^1.19.4",
|
||||||
|
"keycon": "^1.2.0",
|
||||||
|
"overlap-area": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.7.2",
|
"version": "7.7.2",
|
||||||
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.2.tgz",
|
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.2.tgz",
|
||||||
@@ -9765,6 +10015,16 @@
|
|||||||
"vue": "^3.0.0"
|
"vue": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue3-moveable": {
|
||||||
|
"version": "0.28.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/vue3-moveable/-/vue3-moveable-0.28.0.tgz",
|
||||||
|
"integrity": "sha512-vplQO0XkxVEtXMDh2/lZE+c5kMycGXAfYFMvbwFKi8UVYzVk8MTgVHr4fxO9Z+4i4Rb+U/IEIgkhHRMAbx8FJg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"framework-utils": "^1.1.0",
|
||||||
|
"moveable": "~0.53.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vuedraggable": {
|
"node_modules/vuedraggable": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/vuedraggable/-/vuedraggable-4.1.0.tgz",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"vue-draggable-plus": "^0.6.0",
|
"vue-draggable-plus": "^0.6.0",
|
||||||
"vue-i18n": "^9.6.1",
|
"vue-i18n": "^9.6.1",
|
||||||
"vue-router": "^4.0.3",
|
"vue-router": "^4.0.3",
|
||||||
|
"vue3-moveable": "^0.28.0",
|
||||||
"vuedraggable": "^4.1.0",
|
"vuedraggable": "^4.1.0",
|
||||||
"vuex": "^4.0.0",
|
"vuex": "^4.0.0",
|
||||||
"x-sender": "^1.1.6"
|
"x-sender": "^1.1.6"
|
||||||
|
|||||||
17
src/assets/icons/CBrush2.svg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="201.000000pt" height="200.000000pt" viewBox="0 0 201.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M1654 1990 c-26 -8 -153 -110 -162 -129 -1 -3 81 -89 183 -191 l185
|
||||||
|
-185 56 55 c30 30 62 67 70 82 22 41 18 123 -8 176 -29 57 -126 158 -169 176
|
||||||
|
-47 20 -118 27 -155 16z"/>
|
||||||
|
<path d="M868 1243 c-525 -527 -498 -492 -568 -725 -54 -179 -59 -219 -30
|
||||||
|
-248 19 -19 29 -21 64 -16 113 18 361 105 431 152 28 18 251 235 498 481 l447
|
||||||
|
448 -188 188 -187 187 -467 -467z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 799 B |
17
src/assets/icons/CEraser2.svg
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M757 1273 c-214 -214 -402 -406 -418 -427 -32 -43 -37 -82 -15 -124
|
||||||
|
23 -44 327 -338 376 -363 l45 -24 463 -3 462 -3 0 46 0 45 -342 0 -343 0 342
|
||||||
|
343 c187 188 346 352 352 364 16 32 13 74 -7 105 -9 14 -110 116 -224 227
|
||||||
|
l-207 201 -47 0 -48 0 -389 -387z m207 -342 l209 -209 -128 -131 c-76 -78
|
||||||
|
-144 -138 -169 -151 -51 -24 -106 -26 -149 -4 -41 20 -337 314 -337 334 0 13
|
||||||
|
347 370 360 370 3 0 99 -94 214 -209z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 847 B |
20
src/assets/icons/CMarquee.svg
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M250 1545 l0 -205 80 0 80 0 0 -340 0 -340 -80 0 -80 0 0 -205 0
|
||||||
|
-205 205 0 205 0 0 80 0 80 340 0 340 0 0 -80 0 -80 205 0 205 0 0 205 0 205
|
||||||
|
-80 0 -80 0 0 340 0 340 80 0 80 0 0 205 0 205 -205 0 -205 0 0 -80 0 -80
|
||||||
|
-340 0 -340 0 0 80 0 80 -205 0 -205 0 0 -205z m320 0 l0 -125 -120 0 -120 0
|
||||||
|
0 125 0 125 120 0 120 0 0 -125z m1100 0 l0 -125 -120 0 -120 0 0 125 0 125
|
||||||
|
120 0 120 0 0 -125z m-330 -125 l0 -80 85 0 85 0 0 -340 0 -340 -85 0 -85 0 0
|
||||||
|
-80 0 -80 -340 0 -340 0 0 80 0 80 -85 0 -85 0 0 340 0 340 85 0 85 0 0 80 0
|
||||||
|
80 340 0 340 0 0 -80z m-770 -965 l0 -125 -120 0 -120 0 0 125 0 125 120 0
|
||||||
|
120 0 0 -125z m1100 0 l0 -125 -120 0 -120 0 0 125 0 125 120 0 120 0 0 -125z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
68
src/assets/icons/CPart.svg
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="103.000000pt" height="92.000000pt" viewBox="0 0 103.000000 92.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,92.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M365 895 c-5 -2 -36 -6 -67 -10 -45 -5 -58 -10 -59 -23 0 -11 -2 -12
|
||||||
|
-6 -4 -7 17 -32 15 -40 -4 -4 -11 -8 -12 -13 -4 -5 8 -13 9 -21 4 -7 -4 -22
|
||||||
|
-9 -34 -10 -11 -1 -41 -11 -66 -21 l-47 -18 20 -63 c11 -38 23 -60 30 -56 6 4
|
||||||
|
8 -1 3 -15 -3 -11 -3 -21 2 -21 4 0 9 -12 9 -26 1 -14 5 -28 8 -32 4 -3 33 3
|
||||||
|
66 15 33 11 61 19 62 18 2 -2 1 -139 -2 -304 l-5 -301 309 2 309 3 -2 108 c-2
|
||||||
|
77 2 113 11 125 10 12 10 14 1 8 -7 -4 -13 -2 -13 4 0 6 10 8 23 5 18 -5 26
|
||||||
|
-1 36 17 9 17 10 18 6 3 -5 -16 -4 -18 6 -7 18 17 -1 34 -40 37 l-32 2 -2 151
|
||||||
|
c-1 82 0 147 3 144 9 -12 44 -11 52 1 5 8 8 7 8 -4 0 -14 26 -28 52 -29 11 0
|
||||||
|
39 70 33 80 -3 5 1 11 7 13 10 4 9 8 -2 16 -13 10 -8 15 12 12 8 -1 38 91 32
|
||||||
|
98 -2 2 -10 -2 -18 -8 -9 -7 -17 -8 -20 -2 -3 5 0 11 6 14 7 2 -18 14 -56 26
|
||||||
|
-38 12 -71 19 -74 16 -3 -3 -11 0 -18 6 -8 6 -20 9 -28 6 -8 -3 -16 -2 -18 3
|
||||||
|
-5 15 -154 30 -286 29 -70 0 -131 -2 -137 -4z m21 -30 c-6 -18 3 -47 14 -40 4
|
||||||
|
2 18 -7 30 -20 27 -29 17 -34 -14 -7 -20 16 -20 16 -7 -1 23 -29 66 -47 112
|
||||||
|
-47 34 0 40 3 35 16 -5 14 -4 15 9 4 13 -11 19 -9 36 6 12 11 29 35 38 54 15
|
||||||
|
31 20 35 58 35 24 0 43 -2 43 -5 0 -11 115 -27 121 -18 3 5 9 2 13 -7 4 -13
|
||||||
|
14 -16 34 -12 15 2 36 1 47 -4 16 -7 14 -8 -10 -5 l-30 5 32 -14 c39 -18 39
|
||||||
|
-19 14 -83 -15 -38 -17 -52 -8 -61 9 -9 8 -11 -7 -5 -16 6 -18 4 -12 -19 3
|
||||||
|
-14 2 -29 -4 -32 -6 -3 -7 1 -4 9 6 16 -9 20 -73 19 -12 0 -20 4 -17 8 3 5 -4
|
||||||
|
9 -15 9 -20 0 -21 -5 -21 -151 l0 -151 -27 8 c-16 4 -38 7 -50 7 -19 -1 -21 2
|
||||||
|
-13 17 15 28 12 57 -6 57 -11 0 -15 -8 -12 -27 4 -24 1 -27 -23 -26 -15 1 -25
|
||||||
|
4 -22 9 2 4 -2 7 -10 7 -9 0 -14 -10 -14 -25 0 -13 3 -22 8 -19 5 3 6 -1 3 -9
|
||||||
|
-2 -7 0 -25 5 -40 8 -20 7 -25 -3 -21 -7 3 -13 -2 -13 -11 0 -12 7 -15 26 -11
|
||||||
|
14 3 21 3 14 0 -7 -3 -9 -12 -6 -20 3 -7 10 -11 16 -7 5 3 7 1 4 -4 -9 -14 3
|
||||||
|
-74 12 -68 4 2 7 -6 7 -18 -1 -32 32 -34 44 -3 5 14 7 34 5 46 -3 13 0 18 7
|
||||||
|
14 8 -5 9 -1 5 10 -4 9 -3 15 2 12 5 -3 12 1 15 10 3 8 2 12 -4 9 -6 -3 -10
|
||||||
|
-1 -10 4 0 13 3 13 24 5 13 -5 16 -24 16 -103 0 -63 4 -102 13 -111 10 -12 9
|
||||||
|
-12 -4 -2 -13 10 -88 12 -300 10 l-284 -3 3 303 3 302 -26 0 c-14 0 -25 -4
|
||||||
|
-25 -10 0 -5 -7 -6 -17 -3 -9 4 -14 2 -10 -3 4 -6 -6 -9 -24 -6 -28 4 -41 -11
|
||||||
|
-19 -21 6 -3 5 -4 -2 -3 -7 2 -13 11 -13 22 -1 32 -25 104 -35 104 -5 0 -6 7
|
||||||
|
-3 17 4 10 2 14 -5 9 -7 -4 -10 2 -8 17 3 29 14 47 29 47 7 0 3 -8 -8 -17
|
||||||
|
l-20 -16 20 8 c11 4 28 10 37 12 10 3 18 9 18 13 0 4 6 7 12 7 22 -2 158 26
|
||||||
|
158 32 0 3 20 6 45 5 25 0 45 3 45 8 0 4 3 8 6 8 3 0 4 -7 0 -15z m237 -5 c-3
|
||||||
|
-9 1 -8 11 4 9 11 16 15 16 9 0 -6 -7 -16 -15 -23 -8 -7 -15 -9 -15 -4 0 10
|
||||||
|
-29 -28 -30 -40 0 -4 8 -5 17 -2 15 6 15 4 -2 -14 -22 -24 -37 -26 -28 -4 5
|
||||||
|
14 3 15 -15 5 -26 -14 -77 -14 -103 -1 -10 6 -27 27 -38 48 l-19 37 113 0 c95
|
||||||
|
0 112 -2 108 -15z"/>
|
||||||
|
<path d="M346 641 c-3 -5 1 -12 10 -15 23 -9 36 -7 29 4 -3 6 1 7 9 4 9 -3 16
|
||||||
|
-1 16 5 0 13 -56 15 -64 2z"/>
|
||||||
|
<path d="M440 640 c0 -16 33 -26 38 -12 2 7 8 10 13 6 5 -3 9 0 9 5 0 6 -13
|
||||||
|
11 -30 11 -16 0 -30 -5 -30 -10z"/>
|
||||||
|
<path d="M530 641 c0 -12 37 -24 50 -16 20 12 10 25 -20 25 -16 0 -30 -4 -30
|
||||||
|
-9z"/>
|
||||||
|
<path d="M620 641 c0 -12 37 -24 50 -16 20 12 10 25 -20 25 -16 0 -30 -4 -30
|
||||||
|
-9z"/>
|
||||||
|
<path d="M310 593 c0 -20 5 -30 16 -30 10 0 14 8 12 25 -4 37 -28 40 -28 5z"/>
|
||||||
|
<path d="M697 613 c-13 -13 -7 -50 8 -50 10 0 15 10 15 29 0 27 -9 35 -23 21z"/>
|
||||||
|
<path d="M317 534 c-4 -4 -7 -20 -7 -36 0 -35 23 -34 28 1 4 25 -10 46 -21 35z"/>
|
||||||
|
<path d="M692 503 c4 -39 28 -42 28 -4 0 21 -5 31 -16 31 -11 0 -14 -8 -12
|
||||||
|
-27z"/>
|
||||||
|
<path d="M312 415 c4 -33 22 -33 26 0 2 18 -1 25 -13 25 -12 0 -15 -7 -13 -25z"/>
|
||||||
|
<path d="M312 329 c2 -19 8 -33 13 -31 15 3 12 55 -3 60 -10 3 -13 -5 -10 -29z"/>
|
||||||
|
<path d="M342 278 c3 -7 19 -14 37 -16 24 -3 32 0 29 10 -3 7 -19 14 -37 16
|
||||||
|
-24 3 -32 0 -29 -10z"/>
|
||||||
|
<path d="M443 275 c0 -10 10 -15 29 -15 18 0 28 5 28 15 0 10 -10 15 -28 15
|
||||||
|
-19 0 -29 -5 -29 -15z"/>
|
||||||
|
<path d="M530 275 c0 -10 10 -15 33 -15 22 0 28 3 18 9 -11 7 -11 9 0 14 8 3
|
||||||
|
-1 6 -18 6 -23 1 -33 -4 -33 -14z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.1 KiB |
31
src/assets/icons/CPoint.svg
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M346 936 c-21 -13 -49 -41 -62 -62 -41 -67 -27 -180 27 -218 47 -32
|
||||||
|
53 -12 12 40 -71 94 -2 229 116 229 37 0 58 -7 87 -28 32 -22 40 -24 42 -12
|
||||||
|
14 64 -142 100 -222 51z"/>
|
||||||
|
<path d="M368 877 c-33 -28 -48 -57 -48 -96 0 -39 9 -61 26 -61 10 0 14 13 14
|
||||||
|
46 0 57 12 79 50 93 61 21 110 -22 110 -96 0 -48 14 -56 31 -19 31 67 -35 156
|
||||||
|
-114 156 -29 0 -50 -7 -69 -23z"/>
|
||||||
|
<path d="M580 794 c0 -58 -9 -84 -43 -121 -19 -21 -19 -23 -2 -29 34 -13 85
|
||||||
|
75 85 148 0 37 -10 58 -26 58 -10 0 -14 -15 -14 -56z"/>
|
||||||
|
<path d="M410 749 c-13 -6 -28 -15 -32 -22 -4 -7 -8 -106 -8 -222 l-1 -210
|
||||||
|
-27 34 c-62 80 -89 101 -126 101 -27 0 -39 -6 -52 -25 -15 -24 -15 -28 0 -68
|
||||||
|
21 -53 78 -123 94 -113 18 11 16 17 -28 75 -44 58 -48 72 -25 91 21 18 54 -6
|
||||||
|
93 -68 31 -47 74 -78 93 -67 5 4 9 101 9 224 0 225 3 241 42 241 10 0 19 -1
|
||||||
|
19 -2 1 -2 5 -86 8 -188 5 -165 8 -185 24 -188 15 -3 17 5 17 61 0 72 17 100
|
||||||
|
45 77 10 -9 15 -32 15 -77 0 -56 2 -64 18 -61 12 2 16 11 14 34 -5 48 14 86
|
||||||
|
41 82 20 -3 22 -9 25 -66 3 -53 6 -63 20 -60 12 2 19 16 22 43 4 32 10 41 27
|
||||||
|
43 36 5 46 -36 39 -166 -6 -127 -19 -160 -75 -195 -48 -29 -176 -34 -246 -10
|
||||||
|
-48 18 -56 25 -130 128 -16 22 -25 26 -37 19 -15 -8 -11 -18 31 -75 78 -105
|
||||||
|
94 -113 236 -117 119 -3 121 -3 167 27 69 44 82 74 86 214 6 179 -8 221 -72
|
||||||
|
216 -22 -2 -39 4 -55 20 -17 17 -32 22 -55 19 -19 -2 -38 2 -45 9 -6 7 -25 13
|
||||||
|
-40 13 l-29 0 -4 100 c-3 103 -11 122 -53 133 -11 3 -31 1 -45 -4z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
9
src/assets/icons/overallMore.svg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<rect width="24" height="24" fill="url(#pattern0_2641_12790)"/>
|
||||||
|
<defs>
|
||||||
|
<pattern id="pattern0_2641_12790" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||||
|
<use xlink:href="#image0_2641_12790" transform="scale(0.0078125)"/>
|
||||||
|
</pattern>
|
||||||
|
<image id="image0_2641_12790" width="128" height="128" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAACIlJREFUeJztnWlsFVUUgL9OyxNwoVUoCBZFVNxQUaNWo0aiica4SxTUGJe4x+0PBJc/rlH8oSYucQvgQkARixpCECNqgtGKiiigssbK5sLeCvT54/TR+mz75s7cuXfeeL7k/Gpn3jlzZ+5y7rnngKIo/18qfCuQcfYGBgF922QzsA5YD6zxqJeSEBXAWcAEoBHYBeS7kFXAROAaoLcPZRV75IAbgYV03eDdye/AY8BA14or8akHFhGt4YtlKzAWqHRqgRKJAHiC7rv5qPIZsL87UxRT9gCmYL/hO8py4HBXBinhyQFzSbbxC7IBONKNWUpYXsRN43fsCfo6sUwpya24bfyCzEZ9Nt7pD2zEzwuQB65N3kSlOybhr/HziOewj22jdL0ZjiOQsd+0G94MvAe8grxAHwM/A7VAjeG99gK2AJ8aXqdYYAJmX+tO4HGguov7VQBjgCbD+y5D/A+KQ3oAawnfSFuBc0PeeyCwwODeeeAcCzZ1yjHAm8hY43OsK3cZZfjcB2LeE0SV34A3gOHFSowBWlLw8Mpdphc/2JBc5VjPFmB04cePQRvflpxENAJghWNdW4DhATAOcW8q8WgCvox4bSsw06IuYcgB4wJgpOMfzipLkS8rKottKWLAyICulyqKGZtjXr/RihZmVBfGHiU+tTGvH2BFCzOWB8BUDz+cRYYTL7bvFFuKGDANxL/8M/5n0FmQ3UsrQ2qQIcSlrj8B+xQUGIK5R0rlv7KEaCuqpxzr2Yi0+b82NyqBC5CwZo1HaycHXGTw/68gEcJhOR9oILyPvxHZE4jCb8iGVAOy9FRC0ojZF/Yy4XqC0cA2g/u2AodYskkx4DbMu9mliIu9eGIYIBO+hgj3nJuQfUoJqoE/iDbebgPmI3EB85BuOOrYfWnShipdcyd+JpYF+RSNC/RKFfAdfhp/J3Bs8iYqpTgWCcty/QKMdWGcEo5LkNm4q8afinb9qeMukjkTWCwfAr0c2aQYcimwneQafxISj6ikmFOBH7Hb8FuQHka7/TKhJ/AwdnqDD4CDnGqvWKMfMltfjVmjtyATvZPdq6zdTBJUAscjm2qnA4ORl6MvsAlJELUW+ArZmJlH/GgiRVEURVEURQlPGlYBVciRqhOR2XItkmJ1AzJjXo1shf7iS0HFPgESZ/c+4aNhVwLPoVmzypoAuIl4YeitwCykx1DKiKHAR9jzme9C0rbs5dIIJRqXYRb9aiKLEG+bklLuIPm98ybgOFcGKeG5iWQbvqNsoO20i5IOTgWacfcC5IEf6HDeTfFHDf6STU12YJ9Sgmfx0/gFOTN5E5WuOBrYgd8X4Gs0oaI3XsO8wf4CngROQ1zBOaAOybk3nWhh2GGTNSoW2QfzgxNTgP1K3PckZC/A5L5v2zMruxRvBvVCXKxR89XUA/cY/P/Tbf+fD/G/fYFPCL8X8DdwHTIcKcIaJBRte/EfKoEHcZumZA7m2cqH4udoVpZkE/BAx2dfAbzlWIlddJKvNiQPpeAhZkHepG0EcJ2nNk+8nPd1uD2bl2UZEwA3mz1/K8yJce1q/GTVzCI3B8AIDz+8Mub1q6xooYzw5SyJ+7tpCGXLAvkAyQ/omjrP1yvCggB43sMPxyl7MhgtqWqLF0C60zdwO/vchRSqiMLDjnXNqrxOh6G0ErgfcRK4UmAu5o6gQ5GiTL4fXjnLRmB84dkXT6Z6Iq7gqKliTV3BzwB3tylWCnUFxyNPuyu4OakfibIZNJXSxZHrkfy4JvedZs8sxYRXidYtTUDO0/dHtoMHA1cAM9Dt4LLiKPwHhDSiASFeeRp/jd8KnJG8iUp31BAvKXIcmejAPiUE9bgPC/8G2NOFcUo4bsBd469DU6ylkutJflL4K5pNO9VcTHKHQxcCB7gzRYnKwUggiK2G34GsNnTMLyMqkCGhUGc3irQiKVV9BLIolgiQEnUNhN+AWo4cORvmQd/MkobImipkA+pE5FRQLbKnsL5NVgKfIS+AoiiKoiiKoihxScMqIGtUASfQXjCiDol46kd7wYh1SGjWXKRgxCYvmipWqSVeyZh69yorNugJPIadre9ZiMtcKRNOA5Zgd3NrKxJZrcNzyrmcZAtHTkaCY5UUci9uchTMBno7skkJyWW4TVDxDjocpIbj8JOjaLwL45TuqQK+w33j55HDtFogwzOFdHa+5HMSGApMT+f+X6kG3kXW/KZsQ04qNSIewB5IUSxT6oDvkYzoimNux/yLXQxcyX9n8RVI5tMZEe75cUL2KSX4GrOGeolwa/hRmOU7aEVyJFij45hSiZRyOws5oasIOeS5hOUlpFJKWM4DZhJ+OG5EjspHYS2yAdWATCx3MwQ5VuVzkpMFWUw0792TjvVcQIfyOtWYZ+JW6VyuJBo1uM3TnEdqN/Yp5AYy6eKUztkG3Ei0lDTNwPG4rYq6L7AjQDY1lPgsRF6CqHxhSxEDRgXoiVpbrI15/RorWpgxJEDKtSjxiVuuro8VLcz4M0Dq+SrxGUY8V62P7KcfgRRuaMH/DDoLcrLR428nAFY41rUZqfAGwGj0JbAhM4jG1Y71bKaTJetwJGdwk6eHlxW5ovjBlmAQ7hJqNSE5gnd/+UppeiAz/LAPeSvi3g3DIMw9sGdbsEkxZAJmjbQTce/WdHG/AOn2Tb/8ZVhOgKmxZuE4AliE+fPagsT6z0fW+TXAYcCFwIER9LgPeDTCdYoFJuJ3brGG+L4GJQb9EaeZrxfgmuRNVEpxC34afxY6XKeGF3Db+MsoXU9BcUgOu/kOu5N1yARUSRk5kq+3vBxNiZdqAuBxZM1vu/HnAQPcmaLEYQTmUcNdyRYkyYRWOykzckiFsm+J1vDrgUfQrz4TnAk8AXxJ98PDCuA14Cqglw9FQdeWSbMnksq+H7KU24TM7AuiKIrikX8A+4ThOTuVZbQAAAAASUVORK5CYII="/>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.5 KiB |
BIN
src/assets/images/canvas/add.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
src/assets/images/canvas/remove.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
src/assets/images/canvas/shubiao-l.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
src/assets/images/canvas/shubiao-r.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
src/assets/images/icon/xyz.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
@@ -7,6 +7,7 @@ import {
|
|||||||
insertObjectAtZIndex,
|
insertObjectAtZIndex,
|
||||||
removeCanvasObjectByObject,
|
removeCanvasObjectByObject,
|
||||||
createPatternTransform,
|
createPatternTransform,
|
||||||
|
imageAddGapToCanvas,
|
||||||
} from "../utils/helper";
|
} from "../utils/helper";
|
||||||
import { restoreFabricObject } from "../utils/objectHelper";
|
import { restoreFabricObject } from "../utils/objectHelper";
|
||||||
|
|
||||||
@@ -308,16 +309,8 @@ export class FillRepeatGapChangeCommand extends Command {
|
|||||||
await image.decode();
|
await image.decode();
|
||||||
object.fill_.width = image.width;
|
object.fill_.width = image.width;
|
||||||
object.fill_.height = image.height;
|
object.fill_.height = image.height;
|
||||||
// 创建透明 Canvas
|
|
||||||
const tcanvas = document.createElement('canvas');
|
|
||||||
tcanvas.width = image.width + object.fill_.gapX;
|
|
||||||
tcanvas.height = image.height + object.fill_.gapY;
|
|
||||||
const ctx = tcanvas.getContext('2d');
|
|
||||||
ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
|
|
||||||
ctx.drawImage(image, 0, 0);
|
|
||||||
|
|
||||||
const fill = object.get("fill");
|
const fill = object.get("fill");
|
||||||
fill.source = tcanvas;
|
fill.source = imageAddGapToCanvas(image, object.fill_.gapX, object.fill_.gapY);
|
||||||
object.set("fill", new fabric.Pattern(fill));
|
object.set("fill", new fabric.Pattern(fill));
|
||||||
this.canvas.renderAll();
|
this.canvas.renderAll();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -872,13 +872,13 @@ export class ToggleChildLayerVisibilityCommand extends Command {
|
|||||||
// this.oldVisibility = this.childLayer ? this.childLayer.visible : null;
|
// this.oldVisibility = this.childLayer ? this.childLayer.visible : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute() {
|
async execute(visible) {
|
||||||
if (!this.childLayer) {
|
if (!this.childLayer) {
|
||||||
throw new Error("找不到要切换可见性的子图层");
|
throw new Error("找不到要切换可见性的子图层");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换可见性
|
// 切换可见性
|
||||||
this.childLayer.visible = !this.childLayer.visible;
|
this.childLayer.visible = typeof visible === "boolean" ? visible : !this.childLayer.visible;
|
||||||
|
|
||||||
// 更新画布上图层对象的可见性
|
// 更新画布上图层对象的可见性
|
||||||
if (this.canvas) {
|
if (this.canvas) {
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ const canDeleteComputed = computed(() => {
|
|||||||
:is-child="isChild"
|
:is-child="isChild"
|
||||||
:is-active="layer.id === activeLayerId"
|
:is-active="layer.id === activeLayerId"
|
||||||
:is-selected="isLayerSelected(layer.id)"
|
:is-selected="isLayerSelected(layer.id)"
|
||||||
:is-multi-select-mode="isMultiSelectMode && !layer.specialType"
|
:is-multi-select-mode="isMultiSelectMode && !(layer.isPrintTrims || layer.isPrintTrimsGroup)"
|
||||||
:is-editing="editingLayerId === layer.id"
|
:is-editing="editingLayerId === layer.id"
|
||||||
:editing-name="editingLayerName"
|
:editing-name="editingLayerName"
|
||||||
:can-delete="
|
:can-delete="
|
||||||
@@ -296,7 +296,7 @@ const canDeleteComputed = computed(() => {
|
|||||||
:expanded-group-ids="expandedGroupIds"
|
:expanded-group-ids="expandedGroupIds"
|
||||||
@click="(...args) => forwardEvent('layer-click', ...args)"
|
@click="(...args) => forwardEvent('layer-click', ...args)"
|
||||||
@double-click="(...args) => forwardEvent('layer-double-click', ...args)"
|
@double-click="(...args) => forwardEvent('layer-double-click', ...args)"
|
||||||
@context-menu="(...args) => !layer.specialType && forwardEvent('context-menu', ...args)"
|
@context-menu="(...args) => !(layer.isPrintTrims || layer.isPrintTrimsGroup) && forwardEvent('context-menu', ...args)"
|
||||||
@checkbox-change="(...args) => forwardEvent('checkbox-change', ...args)"
|
@checkbox-change="(...args) => forwardEvent('checkbox-change', ...args)"
|
||||||
@toggle-visibility="(...args) => forwardEvent('toggle-visibility', ...args)"
|
@toggle-visibility="(...args) => forwardEvent('toggle-visibility', ...args)"
|
||||||
@toggle-lock="(...args) => forwardEvent('toggle-lock', ...args)"
|
@toggle-lock="(...args) => forwardEvent('toggle-lock', ...args)"
|
||||||
@@ -337,7 +337,7 @@ const canDeleteComputed = computed(() => {
|
|||||||
:expanded-group-ids="expandedGroupIds"
|
:expanded-group-ids="expandedGroupIds"
|
||||||
:isChild="true"
|
:isChild="true"
|
||||||
:parentLayerId="layer.id"
|
:parentLayerId="layer.id"
|
||||||
:group-name="layer.specialType || groupName"
|
:group-name="groupName"
|
||||||
@layer-click="(...args) => forwardEvent('layer-click', ...args)"
|
@layer-click="(...args) => forwardEvent('layer-click', ...args)"
|
||||||
@layer-double-click="(...args) => forwardEvent('layer-double-click', ...args)"
|
@layer-double-click="(...args) => forwardEvent('layer-double-click', ...args)"
|
||||||
@context-menu="(...args) => forwardEvent('context-menu', ...args)"
|
@context-menu="(...args) => forwardEvent('context-menu', ...args)"
|
||||||
|
|||||||
@@ -1242,7 +1242,7 @@ async function handleCrossLevelMove(moveData) {
|
|||||||
try {
|
try {
|
||||||
const layer = findLayerRecursively(layers.value, layerId).layer;
|
const layer = findLayerRecursively(layers.value, layerId).layer;
|
||||||
const toLayer = findLayerRecursively(layers.value, toParentId).layer;
|
const toLayer = findLayerRecursively(layers.value, toParentId).layer;
|
||||||
if(layer?.specialType || toLayer?.specialType) {
|
if(layer?.isPrintTrims || layer?.isPrintTrimsGroup || toLayer?.isPrintTrims || toLayer?.isPrintTrimsGroup) {
|
||||||
console.warn("当前图层不可移动到外部");
|
console.warn("当前图层不可移动到外部");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,479 @@
|
|||||||
|
<template>
|
||||||
|
<transition name="fade">
|
||||||
|
<div
|
||||||
|
class="part-selector-toolbar"
|
||||||
|
v-if="visible"
|
||||||
|
:class="{ active: !closePanel }"
|
||||||
|
>
|
||||||
|
<div class="btn" @click="setClosePanel">
|
||||||
|
<i class="fi fi-br-angle-left"></i>
|
||||||
|
</div>
|
||||||
|
<!-- 顶部选区类型工具栏 -->
|
||||||
|
<div class="toolbar-section">
|
||||||
|
<div class="toolbar-header">
|
||||||
|
<div class="header-title">
|
||||||
|
{{ t("Canvas.GarmentPartSelector") }}
|
||||||
|
</div>
|
||||||
|
<!-- 移除关闭按钮,完全通过工具切换控制显示隐藏 -->
|
||||||
|
<div class="tip">
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src="/src/assets/images/canvas/shubiao-l.png"
|
||||||
|
/>
|
||||||
|
<span>Left Click: Add</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
src="/src/assets/images/canvas/shubiao-r.png"
|
||||||
|
/>
|
||||||
|
<span>Right Click: Remove</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tool-types">
|
||||||
|
<div
|
||||||
|
v-for="item in toolList"
|
||||||
|
:key="item.type"
|
||||||
|
:class="[
|
||||||
|
'tool-btn',
|
||||||
|
{ active: toolType === item.type },
|
||||||
|
]"
|
||||||
|
@click="setPartType(item.type)"
|
||||||
|
>
|
||||||
|
<svg-icon :name="item.icon" :size="item.size" />
|
||||||
|
<span>{{ item.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分割线 -->
|
||||||
|
<div class="toolbar-divider"></div>
|
||||||
|
|
||||||
|
<!-- 底部选区操作工具栏 -->
|
||||||
|
<div class="tool-actions">
|
||||||
|
<div class="action-btn" @click="onCreate">
|
||||||
|
<svg-icon name="CPaste" size="16" />
|
||||||
|
<span class="btn-text">{{
|
||||||
|
$t("Canvas.creation")
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-btn" @click="onCopyCreate">
|
||||||
|
<svg-icon name="CCut" size="26" />
|
||||||
|
<span class="btn-text">{{
|
||||||
|
$t("Canvas.CreateAndCopy")
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, watch } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import {
|
||||||
|
CreateSelectionCommand,
|
||||||
|
InvertSelectionCommand,
|
||||||
|
FeatherSelectionCommand,
|
||||||
|
FillSelectionCommand,
|
||||||
|
} from "../commands/SelectionCommands";
|
||||||
|
import { ToolCommand } from "../commands/ToolCommands";
|
||||||
|
import {
|
||||||
|
LassoCutoutCommand,
|
||||||
|
ClearSelectionCommand,
|
||||||
|
// CutSelectionToNewLayerCommand,
|
||||||
|
} from "../commands/LassoCutoutCommand";
|
||||||
|
|
||||||
|
import { OperationType } from "../utils/layerHelper";
|
||||||
|
import { ClearSelectionContentCommand } from "../commands/ClearSelectionContentCommand";
|
||||||
|
import { CutSelectionToNewLayerCommand } from "../commands/CutSelectionToNewLayerCommand";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
canvas: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
commandManager: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
partManager: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
partManager: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
layerManager: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
toolManager: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
activeTool: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const visible = ref(false);
|
||||||
|
const toolType = ref(OperationType.PART);
|
||||||
|
//打开隐藏操作面板
|
||||||
|
const closePanel = ref(false);
|
||||||
|
const setClosePanel = () => {
|
||||||
|
closePanel.value = !closePanel.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toolList = [
|
||||||
|
{
|
||||||
|
type: OperationType.PART,
|
||||||
|
label: "Point Selection",
|
||||||
|
icon: "CPoint",
|
||||||
|
size: "20",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: OperationType.PART_RECTANGLE,
|
||||||
|
label: "Marquee Selection",
|
||||||
|
icon: "CMarquee",
|
||||||
|
size: "20",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: OperationType.PART_BRUSH,
|
||||||
|
label: "Brush Selection",
|
||||||
|
icon: "CBrush2",
|
||||||
|
size: "16",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: OperationType.PART_ERASER,
|
||||||
|
label: "Erase",
|
||||||
|
icon: "CEraser2",
|
||||||
|
size: "22",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 国际化
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
onMounted(() => {});
|
||||||
|
|
||||||
|
// 监听 activeTool 变化
|
||||||
|
watch(
|
||||||
|
() => props.activeTool,
|
||||||
|
(newTool) => {
|
||||||
|
// 当工具为LASSO或AREA类型时显示选区面板
|
||||||
|
const selectionTools = [
|
||||||
|
OperationType.PART,
|
||||||
|
OperationType.PART_RECTANGLE,
|
||||||
|
OperationType.PART_BRUSH,
|
||||||
|
OperationType.PART_ERASER,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (selectionTools.includes(newTool)) {
|
||||||
|
show();
|
||||||
|
// 根据工具类型设置选区类型
|
||||||
|
toolType.value = newTool;
|
||||||
|
|
||||||
|
// 更新选区管理器的选区类型
|
||||||
|
// if (props.partManager) {
|
||||||
|
// props.partManager.setPartType(toolType.value);
|
||||||
|
// props.partManager.setupPartEvents();
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示面板
|
||||||
|
*/
|
||||||
|
function show() {
|
||||||
|
visible.value = true;
|
||||||
|
closePanel.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭面板
|
||||||
|
*/
|
||||||
|
function close() {
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置选区类型
|
||||||
|
*/
|
||||||
|
function setPartType(type) {
|
||||||
|
toolType.value = type;
|
||||||
|
|
||||||
|
// 通过 ToolManager 切换工具,这会自动通知 partManager
|
||||||
|
if (props.toolManager) {
|
||||||
|
props.toolManager.setToolWithCommand(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 备用方案:如果没有 toolManager,直接更新 partManager
|
||||||
|
// else if (props.partManager) {
|
||||||
|
// props.partManager.setPartType(type);
|
||||||
|
// props.partManager.setupPartEvents();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建
|
||||||
|
function onCreate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
// 复制并创建
|
||||||
|
function onCopyCreate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.part-selector-toolbar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 22px;
|
||||||
|
left: 20px;
|
||||||
|
right: 20px;
|
||||||
|
max-width: min(90vw, 700px);
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: rgba(255, 255, 255, 0.95);
|
||||||
|
backdrop-filter: blur(15px);
|
||||||
|
-webkit-backdrop-filter: blur(15px);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 1000;
|
||||||
|
color: #333;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
user-select: none;
|
||||||
|
&.active {
|
||||||
|
transform: translateY(100%);
|
||||||
|
> .btn {
|
||||||
|
> i {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .btn {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 22px;
|
||||||
|
|
||||||
|
> i {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 平板和手机适配 */
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.part-selector-toolbar {
|
||||||
|
bottom: 15px;
|
||||||
|
left: 15px;
|
||||||
|
right: 15px;
|
||||||
|
max-width: calc(100vw - 30px);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
.part-selector-toolbar {
|
||||||
|
bottom: 10px;
|
||||||
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
max-width: calc(100vw - 20px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.part-selector-toolbar.is-active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-header {
|
||||||
|
// display: flex;
|
||||||
|
// justify-content: center;
|
||||||
|
// align-items: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
// border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
position: relative;
|
||||||
|
> .tip {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-left: 10px;
|
||||||
|
> img {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.header-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #333;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 3px 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
min-width: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-btn:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-btn {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-section {
|
||||||
|
padding: 0 3rem 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-types {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 6px;
|
||||||
|
color: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn span {
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn svg {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn.active {
|
||||||
|
background-color: #007aff;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar-divider {
|
||||||
|
height: 1px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 5px;
|
||||||
|
padding: 0 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 平板适配 - 每行4个按钮 */
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.tool-actions {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 8px 6px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 手机适配 - 每行3个按钮 */
|
||||||
|
@media screen and (max-width: 480px) {
|
||||||
|
.tool-actions {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 6px 4px;
|
||||||
|
padding: 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-btn {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
min-width: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
display: flex;
|
||||||
|
// flex-direction: column;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #333;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0;
|
||||||
|
gap: 4px;
|
||||||
|
.c-svg {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn svg {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-text {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
color: #007aff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="repeat-setting">
|
<div class="repeat-setting">
|
||||||
|
<div class="title">{{ t("Canvas.repeatSetting") }}</div>
|
||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">{{ t("Canvas.angle") }}</span>
|
<span class="label">{{ t("Canvas.angle") }}</span>
|
||||||
<angle-tool
|
<angle-tool
|
||||||
:angle="angle"
|
:angle="angle"
|
||||||
@input="(e) => emit('inputFillAngle', e)"
|
@input="(e) => emit('inputFillAngle', e)"
|
||||||
@change="(e) => emit('changeFillAngle', e)"
|
@change="(e) => emit('changeFillAngle', e)"
|
||||||
|
style-type="2"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
|
||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">{{ t("Canvas.scale") }}</span>
|
<span class="label">{{ t("Canvas.scale") }}</span>
|
||||||
<slider
|
<slider
|
||||||
@@ -22,7 +23,6 @@
|
|||||||
@change="changeFillScale"
|
@change="changeFillScale"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
|
||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">Gap X</span>
|
<span class="label">Gap X</span>
|
||||||
<slider
|
<slider
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
@change="(e) => emit('changeFill_Gap', e, gapY)"
|
@change="(e) => emit('changeFill_Gap', e, gapY)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
|
||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">Gap Y</span>
|
<span class="label">Gap Y</span>
|
||||||
<slider
|
<slider
|
||||||
@@ -50,14 +49,23 @@
|
|||||||
@change="(e) => emit('changeFill_Gap', gapX, e)"
|
@change="(e) => emit('changeFill_Gap', gapX, e)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p></p>
|
|
||||||
<div class="repeat-setting-item">
|
<div class="repeat-setting-item">
|
||||||
<span class="label">{{ t("Canvas.offset") }}</span>
|
<span class="label">{{ t("Canvas.offset") }}</span>
|
||||||
<offset-tool
|
<offset-tool
|
||||||
:top="(props.object.fill?.offsetY / props.object.height) * 100"
|
:left="offsetX"
|
||||||
:left="(props.object.fill?.offsetX / props.object.width) * 100"
|
:top="offsetY"
|
||||||
@input="(e) => emit('inputFillOffset', e)"
|
@input="(e) => emit('inputFillOffset', e)"
|
||||||
@change="(e) => emit('changeFillOffset', e)"
|
@change="(e) => emit('changeFillOffset', e)"
|
||||||
|
:show-dish="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="repeat-setting-item offset">
|
||||||
|
<offset-tool
|
||||||
|
:left="offsetX"
|
||||||
|
:top="offsetY"
|
||||||
|
@input="(e) => emit('inputFillOffset', e)"
|
||||||
|
@change="(e) => emit('changeFillOffset', e)"
|
||||||
|
:show-input="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -88,6 +96,12 @@
|
|||||||
});
|
});
|
||||||
const gapX = computed(() => props.object.fill_?.gapX || 0);
|
const gapX = computed(() => props.object.fill_?.gapX || 0);
|
||||||
const gapY = computed(() => props.object.fill_?.gapY || 0);
|
const gapY = computed(() => props.object.fill_?.gapY || 0);
|
||||||
|
const offsetX = computed(
|
||||||
|
() => (props.object.fill?.offsetX / props.object.width) * 100
|
||||||
|
);
|
||||||
|
const offsetY = computed(
|
||||||
|
() => (props.object.fill?.offsetY / props.object.height) * 100
|
||||||
|
);
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
"inputFillAngle",
|
"inputFillAngle",
|
||||||
"changeFillAngle",
|
"changeFillAngle",
|
||||||
@@ -111,23 +125,36 @@
|
|||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.repeat-setting {
|
.repeat-setting {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
width: 228px;
|
||||||
|
> .title {
|
||||||
|
line-height: 35px;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: -12px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
> .repeat-setting-item {
|
> .repeat-setting-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
//虚线
|
margin-bottom: 10px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
&.offset {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
> .label {
|
> .label {
|
||||||
min-width: 50px;
|
min-width: 68px;
|
||||||
font-size: 14px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
> .angle-tool {
|
&:not(.offset) > div {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
> .slider {
|
||||||
|
--slider-thumb-color1: #000;
|
||||||
|
--slider-thumb-color2: #eee;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
> p {
|
|
||||||
margin: 10px 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 0;
|
|
||||||
border-bottom: 1px dashed #e5e5e5;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -132,7 +132,6 @@
|
|||||||
v-if="v.type === 'rect'"
|
v-if="v.type === 'rect'"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
destroyTooltipOnHide
|
destroyTooltipOnHide
|
||||||
:title="t('Canvas.repeatSetting')"
|
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<repeat-setting
|
<repeat-setting
|
||||||
@@ -164,7 +163,7 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div class="btn">
|
<div class="btn">
|
||||||
<i class="iconfont icon-gengduo"></i>
|
<SvgIcon name="overallMore" size="18" />
|
||||||
</div>
|
</div>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
@@ -179,11 +178,7 @@
|
|||||||
import { ref, onMounted, watch, onUnmounted, reactive } from "vue";
|
import { ref, onMounted, watch, onUnmounted, reactive } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
import {
|
import { OperationType, SpecialLayerId } from "../../utils/layerHelper";
|
||||||
OperationType,
|
|
||||||
SpecialLayerId,
|
|
||||||
SpecialType,
|
|
||||||
} from "../../utils/layerHelper";
|
|
||||||
import { loadImageUrlToLayer } from "../../utils/imageHelper";
|
import { loadImageUrlToLayer } from "../../utils/imageHelper";
|
||||||
import {
|
import {
|
||||||
calculateRotatedTopLeftDeg,
|
calculateRotatedTopLeftDeg,
|
||||||
@@ -284,9 +279,6 @@
|
|||||||
const getActiveObject = (e) => {
|
const getActiveObject = (e) => {
|
||||||
console.log("==========切换激活对象", e, activeObjects);
|
console.log("==========切换激活对象", e, activeObjects);
|
||||||
activeObjects.value = [...e.selected];
|
activeObjects.value = [...e.selected];
|
||||||
// .filter((v) =>
|
|
||||||
// v.specialType ? v.specialType === SpecialType.REPEAT_O : true
|
|
||||||
// );// 过滤出印花对象
|
|
||||||
activeObjects.value.forEach((v) => {
|
activeObjects.value.forEach((v) => {
|
||||||
v.layer = props.layerManager.getLayerById(v.layerId);
|
v.layer = props.layerManager.getLayerById(v.layerId);
|
||||||
});
|
});
|
||||||
@@ -441,7 +433,7 @@
|
|||||||
};
|
};
|
||||||
changeFill(obj, pattern);
|
changeFill(obj, pattern);
|
||||||
};
|
};
|
||||||
// 改变填充便宜
|
// 改变填充偏移
|
||||||
const inputFillOffset = (value, obj) => {
|
const inputFillOffset = (value, obj) => {
|
||||||
if (!obj.oldPattern) obj.oldPattern = obj.get("fill");
|
if (!obj.oldPattern) obj.oldPattern = obj.get("fill");
|
||||||
const pattern = new fabric.Pattern({
|
const pattern = new fabric.Pattern({
|
||||||
@@ -784,6 +776,7 @@
|
|||||||
}
|
}
|
||||||
> .list {
|
> .list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -29,8 +29,12 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
clothingMinIOPath: {
|
||||||
|
type: String,
|
||||||
|
default: "", // 衣服底图URL-线稿
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
console.log(props.clothingMinIOPath)
|
||||||
const commandManager = inject("commandManager");
|
const commandManager = inject("commandManager");
|
||||||
const layerManager = inject("layerManager"); // 图层管理器
|
const layerManager = inject("layerManager"); // 图层管理器
|
||||||
|
|
||||||
@@ -166,6 +170,19 @@ const normalToolsList = ref([
|
|||||||
icon: { name: "CFont", size: "20" },
|
icon: { name: "CFont", size: "20" },
|
||||||
class: "text-btn",
|
class: "text-btn",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: OperationType.PART,
|
||||||
|
title: t("Canvas.GarmentPartSelector"),
|
||||||
|
action: () => selectTool(OperationType.PART),
|
||||||
|
icon: { name: "CPart", size: "28" },
|
||||||
|
class: "part-btn",
|
||||||
|
activeList: [
|
||||||
|
OperationType.PART,
|
||||||
|
OperationType.PART_RECTANGLE,
|
||||||
|
OperationType.PART_BRUSH,
|
||||||
|
OperationType.PART_ERASER,
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "help",
|
id: "help",
|
||||||
title: t("Canvas.help"),
|
title: t("Canvas.help"),
|
||||||
@@ -236,7 +253,13 @@ const redGreenToolsList = ref([
|
|||||||
|
|
||||||
// 根据模式选择工具列表
|
// 根据模式选择工具列表
|
||||||
const toolsList = computed(() => {
|
const toolsList = computed(() => {
|
||||||
return props.isRedGreenMode ? redGreenToolsList.value : normalToolsList.value;
|
const list = props.isRedGreenMode ? redGreenToolsList.value : normalToolsList.value;
|
||||||
|
return list.filter(tool => {
|
||||||
|
if(tool.id === OperationType.PART){
|
||||||
|
return !!props.clothingMinIOPath;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function selectTool(tool, isRedGreenMode = false) {
|
function selectTool(tool, isRedGreenMode = false) {
|
||||||
|
|||||||
@@ -1,32 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="angle-tool" :disabled="disabled">
|
<div class="angle-tool" :disabled="disabled">
|
||||||
<div
|
<template v-if="styleType === '1'">
|
||||||
ref="dishRef"
|
<div
|
||||||
class="dish"
|
ref="dishRef"
|
||||||
@mousedown.stop="mousedown"
|
class="dish"
|
||||||
@touchmove.stop="mousedown"
|
@mousedown.stop="mousedown"
|
||||||
>
|
@touchmove.stop="mousedown"
|
||||||
<div class="pointer" :style="{ transform: `rotate(${angle}deg)` }">
|
>
|
||||||
<span></span>
|
<div
|
||||||
|
class="pointer"
|
||||||
|
:style="{ transform: `rotate(${angle}deg)` }"
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="input">
|
||||||
<div class="input">
|
<input
|
||||||
<input
|
type="number"
|
||||||
type="number"
|
v-model="angle"
|
||||||
v-model="angle"
|
@input="onInput"
|
||||||
@input="onInput"
|
@change="onChange"
|
||||||
@change="onChange"
|
:disabled="disabled"
|
||||||
:disabled="disabled"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
|
|
||||||
|
<my-input
|
||||||
|
v-if="styleType === '2'"
|
||||||
|
v-model="angle"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
type="number"
|
||||||
|
after="°"
|
||||||
|
icon="icon-angle"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
import { calculateAngle } from "../../utils/helper";
|
import { calculateAngle } from "../../utils/helper";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
// Props
|
// Props
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
styleType: {
|
||||||
|
type: String,
|
||||||
|
default: "1",
|
||||||
|
},
|
||||||
angle: {
|
angle: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0,
|
default: 0,
|
||||||
@@ -139,5 +160,8 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
> .my-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="my-input">
|
||||||
|
<span class="decorate"></span>
|
||||||
|
<span v-show="icon" :class="['iconfont', icon]"></span>
|
||||||
|
<span v-show="before" class="before">{{ before }}</span>
|
||||||
|
<input v-bind="$attrs" :value="modelValue" @input="onInput" />
|
||||||
|
<span v-show="after" class="after">{{ after }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Number, default: 0 },
|
||||||
|
icon: { default: "", type: String },
|
||||||
|
before: { default: "", type: String },
|
||||||
|
after: { default: "", type: String },
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["update:modelValue", "input"]);
|
||||||
|
const onInput = (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
emit("update:modelValue", value);
|
||||||
|
emit("input", value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.my-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid rgba(230, 230, 231, 1);
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0 4px 0 2px;
|
||||||
|
> .decorate {
|
||||||
|
width: 2px;
|
||||||
|
background-color: rgba(230, 230, 231, 1);
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 85%;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
> .iconfont {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #000;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
> .before {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #000;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
> .after {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
> input {
|
||||||
|
font-size: 12px;
|
||||||
|
width: 0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,84 +1,100 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="offset-tool">
|
<div class="offset-tool">
|
||||||
|
<div class="input" v-show="showInput">
|
||||||
|
<my-input
|
||||||
|
v-model="left"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
type="number"
|
||||||
|
before="X"
|
||||||
|
after="%"
|
||||||
|
:min="-100"
|
||||||
|
:max="100"
|
||||||
|
/>
|
||||||
|
<my-input
|
||||||
|
v-model="top"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
type="number"
|
||||||
|
before="Y"
|
||||||
|
after="%"
|
||||||
|
:min="-100"
|
||||||
|
:max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="dish"
|
class="dish"
|
||||||
@mousedown="mousedown"
|
@mousedown="mousedown"
|
||||||
@touchstart="mousedown"
|
@touchstart="mousedown"
|
||||||
ref="dishRef"
|
ref="dishRef"
|
||||||
|
v-show="showDish"
|
||||||
>
|
>
|
||||||
<span
|
<img src="/src/assets/images/icon/xyz.png" />
|
||||||
:style="{ top: data.top + '%', left: data.left + '%' }"
|
<span class="ball" :style="ballStyle"></span>
|
||||||
></span>
|
<span class="tip x">X: {{ left }}%</span>
|
||||||
|
<span class="tip y">Y: {{ top }}%</span>
|
||||||
|
<span class="line x"></span>
|
||||||
|
<span class="line y"></span>
|
||||||
|
<span class="line z" :style="lineZStyle"></span>
|
||||||
</div>
|
</div>
|
||||||
<input
|
|
||||||
class="top"
|
|
||||||
type="range"
|
|
||||||
:min="0"
|
|
||||||
:max="100"
|
|
||||||
:step="0.1"
|
|
||||||
v-model="data.top"
|
|
||||||
@input="onInput"
|
|
||||||
@change="onChange"
|
|
||||||
/>
|
|
||||||
<input
|
|
||||||
class="left"
|
|
||||||
type="range"
|
|
||||||
:min="0"
|
|
||||||
:max="100"
|
|
||||||
:step="0.1"
|
|
||||||
v-model="data.left"
|
|
||||||
@input="onInput"
|
|
||||||
@change="onChange"
|
|
||||||
/>
|
|
||||||
<span class="tip"
|
|
||||||
>x:{{ tofix(data.left) }}% y:{{ tofix(data.top) }}%</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch, computed } from "vue";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
top: {
|
|
||||||
type: Number,
|
|
||||||
default: 50,
|
|
||||||
},
|
|
||||||
left: {
|
left: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 50,
|
default: 0,
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
showInput: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
showDish: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const tofix = (v: number | string) => Number(Number(v).toFixed(1));
|
|
||||||
const emit = defineEmits(["change", "input"]);
|
const emit = defineEmits(["change", "input"]);
|
||||||
const data = reactive({
|
// 工具的实际坐标 -100 ~ 100
|
||||||
top: tofix(props.top),
|
const top = ref(Math.round(props.top));
|
||||||
left: tofix(props.left),
|
const left = ref(Math.round(props.left));
|
||||||
});
|
|
||||||
watch(
|
// 原点的坐标 0 ~ 100
|
||||||
() => props.top,
|
const ballStyle = computed(() => ({
|
||||||
(v) => (data.top = tofix(v))
|
top: 50 + Number(top.value) / 2 + "%",
|
||||||
);
|
left: 50 + Number(left.value) / 2 + "%",
|
||||||
|
}));
|
||||||
watch(
|
watch(
|
||||||
() => props.left,
|
() => props.left,
|
||||||
(v) => (data.left = tofix(v))
|
(v) => (left.value = Math.round(v))
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.top,
|
||||||
|
(v) => (top.value = Math.round(v))
|
||||||
);
|
);
|
||||||
const dishRef = ref<HTMLDivElement>();
|
const dishRef = ref<HTMLDivElement>();
|
||||||
const mousedown = (e: MouseEvent | TouchEvent) => {
|
const mousedown = (e: MouseEvent | TouchEvent) => {
|
||||||
if (!dishRef.value) return;
|
if (!dishRef.value) return;
|
||||||
const mousemove = (e: MouseEvent | TouchEvent) => {
|
const mousemove = (e: MouseEvent | TouchEvent) => {
|
||||||
if (!dishRef.value) return;
|
if (!dishRef.value) return;
|
||||||
const { left, top, width, height } =
|
const rect = dishRef.value.getBoundingClientRect();
|
||||||
dishRef.value.getBoundingClientRect();
|
|
||||||
const X = e.clientX || (e as TouchEvent).touches[0].clientX;
|
const X = e.clientX || (e as TouchEvent).touches[0].clientX;
|
||||||
const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
|
const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
|
||||||
var x = ((X - left) / width) * 100;
|
var x = ((X - rect.left) / rect.width) * 100;
|
||||||
var y = ((Y - top) / height) * 100;
|
var y = ((Y - rect.top) / rect.height) * 100;
|
||||||
if (x < 0) x = 0;
|
if (x < 0) x = 0;
|
||||||
if (x > 100) x = 100;
|
if (x > 100) x = 100;
|
||||||
if (y < 0) y = 0;
|
if (y < 0) y = 0;
|
||||||
if (y > 100) y = 100;
|
if (y > 100) y = 100;
|
||||||
data.left = tofix(x);
|
left.value = Math.round((x - 50) * 2);
|
||||||
data.top = tofix(y);
|
top.value = Math.round((y - 50) * 2);
|
||||||
onInput();
|
onInput();
|
||||||
};
|
};
|
||||||
mousemove(e);
|
mousemove(e);
|
||||||
@@ -94,96 +110,125 @@
|
|||||||
document.addEventListener("mouseup", mouseup);
|
document.addEventListener("mouseup", mouseup);
|
||||||
document.addEventListener("touchend", mouseup);
|
document.addEventListener("touchend", mouseup);
|
||||||
};
|
};
|
||||||
const onInput = () => emit("input", { ...data });
|
const onInput = () => {
|
||||||
|
emit("input", { left: left.value, top: top.value });
|
||||||
|
};
|
||||||
var changeTime: any = null;
|
var changeTime: any = null;
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
clearTimeout(changeTime);
|
clearTimeout(changeTime);
|
||||||
changeTime = setTimeout(() => emit("change", { ...data }), 500);
|
changeTime = setTimeout(() => {
|
||||||
|
emit("change", {
|
||||||
|
left: left.value,
|
||||||
|
top: top.value,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
};
|
};
|
||||||
// var offsetTime = null;
|
const lineZStyle = computed(() => ({
|
||||||
// watch(data, (v) => {
|
"--rotateZ": calculateAngle(0, 0, left.value, top.value) + "deg",
|
||||||
// const obj = { ...v };
|
width: calculateDistance(0, 0, left.value, top.value) / 2 + "%",
|
||||||
// emit("input", obj);
|
}));
|
||||||
// clearTimeout(offsetTime);
|
// 计算角度
|
||||||
// offsetTime = setTimeout(() => emit("change", obj), 50);
|
function calculateAngle(x1: number, y1: number, x2: number, y2: number) {
|
||||||
// });
|
const deltaX = x2 - x1;
|
||||||
|
const deltaY = y1 - y2;
|
||||||
// defineExpose({
|
let angle = Math.atan2(deltaX, deltaY) * (180 / Math.PI) - 90;
|
||||||
// open,
|
return angle;
|
||||||
// close,
|
}
|
||||||
// });
|
// 计算距离
|
||||||
|
function calculateDistance(x1: number, y1: number, x2: number, y2: number) {
|
||||||
|
const deltaX = x2 - x1;
|
||||||
|
const deltaY = y2 - y1;
|
||||||
|
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.offset-tool {
|
.offset-tool {
|
||||||
width: 125px;
|
|
||||||
height: 125px;
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
> .input {
|
||||||
--gap: 15px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 12px;
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
> .dish {
|
> .dish {
|
||||||
margin: var(--gap) 0 0 var(--gap);
|
width: 135px;
|
||||||
flex: 1;
|
height: 135px;
|
||||||
border: 1px solid #000;
|
border: 1px solid #eaeaea;
|
||||||
border-radius: 5px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: #fff;
|
background-color: #f6f6f6;
|
||||||
> span {
|
margin-top: 24px;
|
||||||
|
> * {
|
||||||
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
position: absolute;
|
}
|
||||||
top: 0%;
|
> img {
|
||||||
left: 0%;
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
bottom: 4px;
|
||||||
|
right: 4px;
|
||||||
|
}
|
||||||
|
> .ball {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
width: 8px;
|
width: 10px;
|
||||||
height: 8px;
|
height: 10px;
|
||||||
background-color: #000;
|
border: 1px solid #fff;
|
||||||
|
background-color: #333;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 0.68px 1.7px 0px rgba(0, 0, 0, 0.26);
|
||||||
}
|
}
|
||||||
}
|
> .tip {
|
||||||
> .tip {
|
font-size: 10px;
|
||||||
position: absolute;
|
color: #000;
|
||||||
right: 4px;
|
line-height: 24px;
|
||||||
bottom: 0;
|
&.x {
|
||||||
font-size: 10px;
|
top: 50%;
|
||||||
pointer-events: none;
|
right: 0%;
|
||||||
user-select: none;
|
transform: translate(100%, -50%);
|
||||||
color: #666;
|
padding-left: 6px;
|
||||||
}
|
}
|
||||||
> input.left {
|
&.y {
|
||||||
right: 0;
|
top: 0%;
|
||||||
}
|
left: 50%;
|
||||||
> input.top {
|
transform: translate(-50%, -100%);
|
||||||
bottom: 0;
|
}
|
||||||
left: 0;
|
|
||||||
transform-origin: left bottom;
|
|
||||||
transform: rotate(90deg) translateX(-100%);
|
|
||||||
}
|
|
||||||
> input {
|
|
||||||
position: absolute;
|
|
||||||
width: calc(100% - var(--gap));
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 8px;
|
|
||||||
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
|
|
||||||
// outline: none;
|
|
||||||
&::-webkit-slider-thumb {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #4285f4; /* 蓝色滑块 */
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
}
|
||||||
&::-webkit-slider-thumb:hover {
|
> .line {
|
||||||
background: #3b77db;
|
border-color: #d9d9d9;
|
||||||
transform: scale(1.1);
|
border-style: dashed;
|
||||||
|
border-width: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
&.x {
|
||||||
|
width: 100%;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
&.y {
|
||||||
|
height: 100%;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
&.z {
|
||||||
|
width: 50%;
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-color: #454754;
|
||||||
|
transform: translate(0%, -50%) rotateZ(var(--rotateZ));
|
||||||
|
transform-origin: left center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="slider" :disabled="disabled">
|
<div class="slider" :disabled="disabled">
|
||||||
<div class="input-range">
|
<div
|
||||||
<span
|
class="input-range"
|
||||||
class="tip"
|
:style="{
|
||||||
:style="{
|
'--progress': (value - props.min) / (props.max - props.min),
|
||||||
'--progress': (value - props.min) / (props.max - props.min),
|
}"
|
||||||
}"
|
>
|
||||||
>{{ props.tipFormatter(value) }}</span
|
<span class="tip">{{ props.tipFormatter(value) }}</span>
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="range"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
@@ -20,8 +19,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="input" v-show="isInput">
|
<div class="input" v-show="isInput">
|
||||||
<input
|
<my-input
|
||||||
type="number"
|
|
||||||
v-model="value"
|
v-model="value"
|
||||||
:min="props.min"
|
:min="props.min"
|
||||||
:max="props.max"
|
:max="props.max"
|
||||||
@@ -29,6 +27,7 @@
|
|||||||
@input="onInput"
|
@input="onInput"
|
||||||
@change="onChange"
|
@change="onChange"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
type="number"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,6 +35,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -86,9 +86,10 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
--input-thumb-size: 12px;
|
|
||||||
width: 150px;
|
width: 150px;
|
||||||
// &:focus-within,
|
--input-thumb-size: 10px;
|
||||||
|
--backcolor1: var(--slider-thumb-color1, #4285f4);
|
||||||
|
--backcolor2: var(--slider-thumb-color2, rgba(0, 0, 0, 0.1));
|
||||||
&:hover {
|
&:hover {
|
||||||
> .input-range > .tip {
|
> .input-range > .tip {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -103,21 +104,26 @@
|
|||||||
appearance: none;
|
appearance: none;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background: rgba(0, 0, 0, 0.1); /* 更柔和的颜色 */
|
|
||||||
outline: none;
|
outline: none;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
var(--backcolor1) 0%,
|
||||||
|
var(--backcolor1) calc(var(--progress) * 100%),
|
||||||
|
var(--backcolor2) calc(var(--progress) * 100%),
|
||||||
|
var(--backcolor2) 100%
|
||||||
|
);
|
||||||
&::-webkit-slider-thumb {
|
&::-webkit-slider-thumb {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
width: var(--input-thumb-size);
|
width: var(--input-thumb-size);
|
||||||
height: var(--input-thumb-size);
|
height: var(--input-thumb-size);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: #4285f4; /* 蓝色滑块 */
|
background: var(--backcolor1); /* 蓝色滑块 */
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
&::-webkit-slider-thumb:hover {
|
&::-webkit-slider-thumb:hover {
|
||||||
background: #3b77db;
|
|
||||||
transform: scale(1.1);
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { KeyboardManager } from "./managers/events/KeyboardManager.js";
|
|||||||
import CanvasConfig from "./config/canvasConfig.js";
|
import CanvasConfig from "./config/canvasConfig.js";
|
||||||
import { LiquifyManager } from "./managers/liquify/LiquifyManager";
|
import { LiquifyManager } from "./managers/liquify/LiquifyManager";
|
||||||
import { SelectionManager } from "./managers/selection/SelectionManager";
|
import { SelectionManager } from "./managers/selection/SelectionManager";
|
||||||
|
import { PartManager } from "./managers/PartManager";
|
||||||
import { RedGreenModeManager } from "./managers/RedGreenModeManager";
|
import { RedGreenModeManager } from "./managers/RedGreenModeManager";
|
||||||
import texturePresetManager from "./managers/brushes/TexturePresetManager";
|
import texturePresetManager from "./managers/brushes/TexturePresetManager";
|
||||||
import { BrushStore } from "./store/BrushStore";
|
import { BrushStore } from "./store/BrushStore";
|
||||||
@@ -38,6 +39,7 @@ import LiquifyPanel from "./components/LiquifyPanel.vue"; // 引入液化编辑
|
|||||||
import PalletPanel from "./components/PalletPanel/index.vue";
|
import PalletPanel from "./components/PalletPanel/index.vue";
|
||||||
import SelectMenuPanel from "./components/SelectMenuPanel/index.vue"; // 引入选择工具菜单组件
|
import SelectMenuPanel from "./components/SelectMenuPanel/index.vue"; // 引入选择工具菜单组件
|
||||||
import SelectionPanel from "./components/SelectionPanel.vue"; // 引入选区面板
|
import SelectionPanel from "./components/SelectionPanel.vue"; // 引入选区面板
|
||||||
|
import PartSelectorPanel from "./components/PartSelectorPanel.vue"; // 引入部件选取面板
|
||||||
import { LayerType, OperationType } from "./utils/layerHelper.js";
|
import { LayerType, OperationType } from "./utils/layerHelper.js";
|
||||||
import { ToolManager } from "./managers/ToolManager.js";
|
import { ToolManager } from "./managers/ToolManager.js";
|
||||||
import { fabric } from "fabric-with-all";
|
import { fabric } from "fabric-with-all";
|
||||||
@@ -45,6 +47,7 @@ import {
|
|||||||
uploadImageAndCreateLayer,
|
uploadImageAndCreateLayer,
|
||||||
loadImageUrlToLayer,
|
loadImageUrlToLayer,
|
||||||
loadImage,
|
loadImage,
|
||||||
|
resizeImage,
|
||||||
} from "./utils/imageHelper.js";
|
} from "./utils/imageHelper.js";
|
||||||
import { optimizeCanvasRendering } from "./utils/helper";
|
import { optimizeCanvasRendering } from "./utils/helper";
|
||||||
// import MinimapPanel from "./components/MinimapPanel.vue";
|
// import MinimapPanel from "./components/MinimapPanel.vue";
|
||||||
@@ -84,6 +87,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false, // 是否启用红绿图模式
|
default: false, // 是否启用红绿图模式
|
||||||
},
|
},
|
||||||
|
clothingMinIOPath: {
|
||||||
|
type: String,
|
||||||
|
default: "", // 衣服底图URL-线稿
|
||||||
|
},
|
||||||
clothingImageUrl: {
|
clothingImageUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "", // 衣服底图URL-线稿
|
default: "", // 衣服底图URL-线稿
|
||||||
@@ -184,6 +191,7 @@ let keyboardManager = null;
|
|||||||
let toolManager = null;
|
let toolManager = null;
|
||||||
let liquifyManager = null;
|
let liquifyManager = null;
|
||||||
let selectionManager = null;
|
let selectionManager = null;
|
||||||
|
let partManager = null;
|
||||||
let redGreenModeManager = null;
|
let redGreenModeManager = null;
|
||||||
|
|
||||||
// 快捷键帮助模态框状态
|
// 快捷键帮助模态框状态
|
||||||
@@ -225,6 +233,7 @@ function handleCanvasInit(isLoadJson = false) {
|
|||||||
keyboardManager,
|
keyboardManager,
|
||||||
liquifyManager,
|
liquifyManager,
|
||||||
selectionManager,
|
selectionManager,
|
||||||
|
partManager,
|
||||||
redGreenModeManager,
|
redGreenModeManager,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -374,9 +383,20 @@ onMounted(async () => {
|
|||||||
selectionManager = new SelectionManager({
|
selectionManager = new SelectionManager({
|
||||||
canvas: canvasManager.canvas,
|
canvas: canvasManager.canvas,
|
||||||
layerManager,
|
layerManager,
|
||||||
|
props,
|
||||||
});
|
});
|
||||||
canvasManager.setSelectionManager(selectionManager);
|
canvasManager.setSelectionManager(selectionManager);
|
||||||
|
|
||||||
|
// 初始化部件选择管理器
|
||||||
|
partManager = new PartManager({
|
||||||
|
canvas: canvasManager.canvas,
|
||||||
|
layerManager,
|
||||||
|
canvasManager,
|
||||||
|
toolManager,
|
||||||
|
props,
|
||||||
|
});
|
||||||
|
canvasManager.setPartManager(partManager);
|
||||||
|
|
||||||
if (props.canvasJSON) {
|
if (props.canvasJSON) {
|
||||||
// 如果传入了初始JSON数据,加载到画布上
|
// 如果传入了初始JSON数据,加载到画布上
|
||||||
if (typeof props.canvasJSON === "string") {
|
if (typeof props.canvasJSON === "string") {
|
||||||
@@ -536,6 +556,7 @@ onBeforeUnmount(async () => {
|
|||||||
toolManager?.dispose?.();
|
toolManager?.dispose?.();
|
||||||
liquifyManager?.dispose?.();
|
liquifyManager?.dispose?.();
|
||||||
selectionManager?.dispose?.();
|
selectionManager?.dispose?.();
|
||||||
|
partManager?.dispose?.();
|
||||||
redGreenModeManager?.dispose?.();
|
redGreenModeManager?.dispose?.();
|
||||||
// minimapManager?.dispose?.();
|
// minimapManager?.dispose?.();
|
||||||
canvasManager = null;
|
canvasManager = null;
|
||||||
@@ -545,6 +566,7 @@ onBeforeUnmount(async () => {
|
|||||||
toolManager = null;
|
toolManager = null;
|
||||||
liquifyManager = null;
|
liquifyManager = null;
|
||||||
selectionManager = null;
|
selectionManager = null;
|
||||||
|
partManager = null;
|
||||||
redGreenModeManager = null;
|
redGreenModeManager = null;
|
||||||
// fabric.Object.prototype.controls.deleteControl = undefined;
|
// fabric.Object.prototype.controls.deleteControl = undefined;
|
||||||
|
|
||||||
@@ -709,8 +731,13 @@ function addRemoveBtn(fun) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteFun() {
|
function deleteFun(e, control) {
|
||||||
removeLayer(layerManager.activeLayerId.value);
|
const target = control.target;
|
||||||
|
if(target.onDelete){
|
||||||
|
target.onDelete(target);
|
||||||
|
}else if(target.id){
|
||||||
|
removeLayer(layerManager.activeLayerId.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeLayer(layerId) {
|
function removeLayer(layerId) {
|
||||||
@@ -995,26 +1022,38 @@ defineExpose({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
// 导出图片
|
// 导出图片
|
||||||
exportImage: ({
|
exportImage: async ({
|
||||||
isContainBg = false, // 是否包含背景图层
|
isContainBg = false, // 是否包含背景图层
|
||||||
isContainFixed = false, // 是否包含固定图层
|
isContainFixed = false, // 是否包含固定图层
|
||||||
isContainFixedOther = false, // 是否包含其他固定图层
|
isContainFixedOther = true, // 是否包含其他固定图层--颜色图层
|
||||||
|
isPrintTrimsNoRepeat = true, // 是否包含印花图层的不平铺
|
||||||
|
isPrintTrimsRepeat = true, // 是否包含印花图层的平铺
|
||||||
|
isContainNormalLayer = true, // 是否包含普通图层
|
||||||
isCropByBg = false, // 是否使用背景大小裁剪 // 如果为true,则导出时裁剪到背景图层大小
|
isCropByBg = false, // 是否使用背景大小裁剪 // 如果为true,则导出时裁剪到背景图层大小
|
||||||
layerId = "", // 导出具体图层ID
|
layerId = "", // 导出具体图层ID
|
||||||
layerIdArray = [], // 导出多个图层ID数组
|
layerIdArray = [], // 导出多个图层ID数组
|
||||||
expPicType = "png", // 导出图片类型 JPG 或 PNG ,SVG
|
expPicType = "png", // 导出图片类型 JPG 或 PNG ,SVG
|
||||||
isEnhanceImg, // 是否是增强图片
|
isEnhanceImg, // 是否是增强图片
|
||||||
|
width = 0,// 导出的图片宽度
|
||||||
|
height = 0, // 导出的图片高度
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
return canvasManager.exportImage({
|
var base64 = await canvasManager.exportImage({
|
||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther,
|
isContainFixedOther,
|
||||||
|
isPrintTrimsNoRepeat,
|
||||||
|
isPrintTrimsRepeat,
|
||||||
|
isContainNormalLayer,
|
||||||
isCropByBg,
|
isCropByBg,
|
||||||
layerId,
|
layerId,
|
||||||
layerIdArray,
|
layerIdArray,
|
||||||
expPicType,
|
expPicType,
|
||||||
isEnhanceImg,
|
isEnhanceImg,
|
||||||
});
|
});
|
||||||
|
if(width > 0 && height > 0){
|
||||||
|
base64 = await resizeImage(base64, width, height);
|
||||||
|
}
|
||||||
|
return base64;
|
||||||
},
|
},
|
||||||
// 导出颜色图层
|
// 导出颜色图层
|
||||||
exportColorLayer: () => {
|
exportColorLayer: () => {
|
||||||
@@ -1177,6 +1216,7 @@ defineExpose({
|
|||||||
v-if="canvasManagerLoaded"
|
v-if="canvasManagerLoaded"
|
||||||
:activeTool="activeTool"
|
:activeTool="activeTool"
|
||||||
:isRedGreenMode="isRedGreenMode"
|
:isRedGreenMode="isRedGreenMode"
|
||||||
|
:clothingMinIOPath="props.clothingMinIOPath"
|
||||||
@tool-selected="handleToolSelect"
|
@tool-selected="handleToolSelect"
|
||||||
@red-green-tool-selected="handleRedGreenToolSelect"
|
@red-green-tool-selected="handleRedGreenToolSelect"
|
||||||
@toggle-red-green-mode="toggleRedGreenMode"
|
@toggle-red-green-mode="toggleRedGreenMode"
|
||||||
@@ -1248,6 +1288,19 @@ defineExpose({
|
|||||||
:activeTool="activeTool"
|
:activeTool="activeTool"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 部件选取面板 -->
|
||||||
|
<PartSelectorPanel
|
||||||
|
v-if="canvasManagerLoaded && !enabledRedGreenMode"
|
||||||
|
:canvas="canvasManager && canvasManager.canvas"
|
||||||
|
:commandManager="commandManager"
|
||||||
|
:selectionManager="selectionManager"
|
||||||
|
:partManager="partManager"
|
||||||
|
:layerManager="layerManager"
|
||||||
|
:canvasManager="canvasManager"
|
||||||
|
:toolManager="toolManager"
|
||||||
|
:activeTool="activeTool"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 文本编辑面板 -->
|
<!-- 文本编辑面板 -->
|
||||||
<TextEditorPanel
|
<TextEditorPanel
|
||||||
v-if="canvasManagerLoaded && !enabledRedGreenMode"
|
v-if="canvasManagerLoaded && !enabledRedGreenMode"
|
||||||
@@ -1401,6 +1454,7 @@ defineExpose({
|
|||||||
/* background-color: #f8f8f8; */
|
/* background-color: #f8f8f8; */
|
||||||
:deep(.canvas-container) {
|
:deep(.canvas-container) {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
|
filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1413,33 +1467,31 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.background-grid {
|
.background-grid {
|
||||||
--offsetX: 0px;
|
--offsetX: 50%;
|
||||||
--offsetY: 0px;
|
--offsetY: 50%;
|
||||||
--size: 8px;
|
--size: 10px;
|
||||||
--color: #dedcdc;
|
--color: rgba(229, 229,229,0.5);
|
||||||
background-image: -webkit-linear-gradient(
|
background-image: -webkit-linear-gradient(
|
||||||
45deg,
|
90deg,
|
||||||
var(--color) 25%,
|
var(--color) 1px,
|
||||||
transparent 0,
|
transparent 0,
|
||||||
transparent 75%,
|
|
||||||
var(--color) 0
|
|
||||||
),
|
),
|
||||||
-webkit-linear-gradient(45deg, var(--color) 25%, transparent 0, transparent
|
-webkit-linear-gradient(
|
||||||
75%, var(--color) 0);
|
0,
|
||||||
background-image: linear-gradient(
|
var(--color) 1px,
|
||||||
45deg,
|
transparent 0,
|
||||||
var(--color) 25%,
|
);
|
||||||
|
background-image:linear-gradient(
|
||||||
|
90deg,
|
||||||
|
var(--color) 1px,
|
||||||
transparent 0,
|
transparent 0,
|
||||||
transparent 75%,
|
|
||||||
var(--color) 0
|
|
||||||
),
|
),
|
||||||
linear-gradient(
|
linear-gradient(
|
||||||
45deg,
|
0,
|
||||||
var(--color) 25%,
|
var(--color) 1px,
|
||||||
transparent 0,
|
transparent 0,
|
||||||
transparent 75%,
|
|
||||||
var(--color) 0
|
|
||||||
);
|
);
|
||||||
|
background-color: #fafafa;
|
||||||
background-position: var(--offsetX) var(--offsetY),
|
background-position: var(--offsetX) var(--offsetY),
|
||||||
calc(var(--size) + var(--offsetX)) calc(var(--size) + var(--offsetY));
|
calc(var(--size) + var(--offsetX)) calc(var(--size) + var(--offsetY));
|
||||||
background-size: calc(var(--size) * 2) calc(var(--size) * 2);
|
background-size: calc(var(--size) * 2) calc(var(--size) * 2);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
createLayer,
|
createLayer,
|
||||||
LayerType,
|
LayerType,
|
||||||
SpecialLayerId,
|
SpecialLayerId,
|
||||||
SpecialType,
|
|
||||||
BlendMode,
|
BlendMode,
|
||||||
} from "../utils/layerHelper";
|
} from "../utils/layerHelper";
|
||||||
import { ObjectMoveCommand } from "../commands/ObjectCommands";
|
import { ObjectMoveCommand } from "../commands/ObjectCommands";
|
||||||
@@ -35,6 +34,7 @@ import {
|
|||||||
createPatternTransform,
|
createPatternTransform,
|
||||||
getTransformScaleAngle,
|
getTransformScaleAngle,
|
||||||
base64ToCanvas,
|
base64ToCanvas,
|
||||||
|
imageAddGapToCanvas,
|
||||||
} from "../utils/helper";
|
} from "../utils/helper";
|
||||||
import { ChangeFixedImageCommand } from "../commands/ObjectLayerCommands";
|
import { ChangeFixedImageCommand } from "../commands/ObjectLayerCommands";
|
||||||
import { isFunction } from "lodash-es";
|
import { isFunction } from "lodash-es";
|
||||||
@@ -45,7 +45,7 @@ import {
|
|||||||
} from "../utils/layerUtils";
|
} from "../utils/layerUtils";
|
||||||
import { imageModeHandler } from "../utils/imageHelper";
|
import { imageModeHandler } from "../utils/imageHelper";
|
||||||
import { getObjectAlphaToCanvas } from "../utils/objectHelper";
|
import { getObjectAlphaToCanvas } from "../utils/objectHelper";
|
||||||
import { AddLayerCommand, RemoveLayerCommand } from "../commands/LayerCommands";
|
import { AddLayerCommand, RemoveLayerCommand, ToggleChildLayerVisibilityCommand } from "../commands/LayerCommands";
|
||||||
import { fa, id } from "element-plus/es/locales.mjs";
|
import { fa, id } from "element-plus/es/locales.mjs";
|
||||||
import i18n from "@/lang/index.ts";
|
import i18n from "@/lang/index.ts";
|
||||||
const {t} = i18n.global;
|
const {t} = i18n.global;
|
||||||
@@ -305,6 +305,19 @@ export class CanvasManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置部件选择管理器
|
||||||
|
* @param {Object} partManager 部件选择管理器实例
|
||||||
|
*/
|
||||||
|
setPartManager(partManager) {
|
||||||
|
this.partManager = partManager;
|
||||||
|
|
||||||
|
// 如果已创建事件管理器,更新它的部件选择管理器引用
|
||||||
|
if (this.eventManager) {
|
||||||
|
this.eventManager.partManager = this.partManager;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 设置红绿图模式管理器
|
// 设置红绿图模式管理器
|
||||||
setRedGreenModeManager(redGreenModeManager) {
|
setRedGreenModeManager(redGreenModeManager) {
|
||||||
this.redGreenModeManager = redGreenModeManager;
|
this.redGreenModeManager = redGreenModeManager;
|
||||||
@@ -717,6 +730,8 @@ export class CanvasManager {
|
|||||||
originX: backgroundLayerObject.originX || "left",
|
originX: backgroundLayerObject.originX || "left",
|
||||||
originY: backgroundLayerObject.originY || "top",
|
originY: backgroundLayerObject.originY || "top",
|
||||||
absolutePositioned: true,
|
absolutePositioned: true,
|
||||||
|
rx: 15,
|
||||||
|
ry: 15,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getBackgroundLayer() {
|
getBackgroundLayer() {
|
||||||
@@ -827,7 +842,7 @@ export class CanvasManager {
|
|||||||
updateMaskPosition(backgroundLayerObject) {
|
updateMaskPosition(backgroundLayerObject) {
|
||||||
if (!backgroundLayerObject || !this.maskLayer || !this.canvas.clipPath)
|
if (!backgroundLayerObject || !this.maskLayer || !this.canvas.clipPath)
|
||||||
return;
|
return;
|
||||||
|
console.log("backgroundLayerObject");
|
||||||
const left = backgroundLayerObject.left;
|
const left = backgroundLayerObject.left;
|
||||||
const top = backgroundLayerObject.top;
|
const top = backgroundLayerObject.top;
|
||||||
|
|
||||||
@@ -922,6 +937,9 @@ export class CanvasManager {
|
|||||||
* @param {Boolean} options.isContainBg 是否包含背景图层
|
* @param {Boolean} options.isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} options.isContainFixed 是否包含固定图层
|
* @param {Boolean} options.isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} options.isPrintTrimsNoRepeat 是否包含印花图层的不平铺
|
||||||
|
* @param {Boolean} options.isPrintTrimsRepeat 是否包含印花图层的平铺
|
||||||
|
* @param {Boolean} options.isContainNormalLayer 是否包含普通图层
|
||||||
* @param {String} options.layerId 导出具体图层ID
|
* @param {String} options.layerId 导出具体图层ID
|
||||||
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
||||||
* @param {String} options.expPicType 导出图片类型 (png/jpg/svg)
|
* @param {String} options.expPicType 导出图片类型 (png/jpg/svg)
|
||||||
@@ -942,6 +960,9 @@ export class CanvasManager {
|
|||||||
// this.canvas.renderAll(); // 重新渲染画布
|
// this.canvas.renderAll(); // 重新渲染画布
|
||||||
// 自动设置红绿图模式相关参数
|
// 自动设置红绿图模式相关参数
|
||||||
const enhancedOptions = {
|
const enhancedOptions = {
|
||||||
|
isPrintTrimsNoRepeat: true,
|
||||||
|
isPrintTrimsRepeat: true,
|
||||||
|
isContainNormalLayer: true,
|
||||||
...options,
|
...options,
|
||||||
// 如果没有明确指定,则根据当前模式自动设置
|
// 如果没有明确指定,则根据当前模式自动设置
|
||||||
restoreOpacityInRedGreen:
|
restoreOpacityInRedGreen:
|
||||||
@@ -972,7 +993,46 @@ export class CanvasManager {
|
|||||||
console.log("红绿图模式导出图层:", normalLayerIds);
|
console.log("红绿图模式导出图层:", normalLayerIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await this.exportManager.exportImage(enhancedOptions);
|
|
||||||
|
// 处理特殊图层的显示状态
|
||||||
|
const ptlids = [];
|
||||||
|
if(!enhancedOptions.isPrintTrimsNoRepeat || !enhancedOptions.isPrintTrimsRepeat){
|
||||||
|
let layers = this.layers?.value?.find((layer) => layer.isPrintTrimsGroup)?.children || [];
|
||||||
|
for(let layer of layers){
|
||||||
|
if(!layer.visible) continue;
|
||||||
|
let repeat = layer.fabricObjects?.[0]?.fill?.repeat || "no-repeat";
|
||||||
|
if(typeof repeat !== "string") repeat = "no-repeat";
|
||||||
|
if(repeat === "no-repeat"){
|
||||||
|
if(enhancedOptions.isPrintTrimsNoRepeat) continue;
|
||||||
|
}else{
|
||||||
|
if(enhancedOptions.isPrintTrimsRepeat) continue;
|
||||||
|
}
|
||||||
|
ptlids.push(layer.id);
|
||||||
|
const command = new ToggleChildLayerVisibilityCommand({
|
||||||
|
canvas: this.canvas,
|
||||||
|
layers: this.layers,
|
||||||
|
layerId: layer.id,
|
||||||
|
layerManager: this.layerManager,
|
||||||
|
});
|
||||||
|
await command.execute(false);
|
||||||
|
}
|
||||||
|
await this.changeCanvas();
|
||||||
|
}
|
||||||
|
const res = await this.exportManager.exportImage(enhancedOptions);
|
||||||
|
// 恢复特殊图层的显示状态
|
||||||
|
if(ptlids.length > 0){
|
||||||
|
for(let id of ptlids){
|
||||||
|
const command = new ToggleChildLayerVisibilityCommand({
|
||||||
|
canvas: this.canvas,
|
||||||
|
layers: this.layers,
|
||||||
|
layerId: id,
|
||||||
|
layerManager: this.layerManager,
|
||||||
|
});
|
||||||
|
await command.execute(true);
|
||||||
|
}
|
||||||
|
await this.changeCanvas();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn("CanvasManager导出图片失败:", error);
|
console.warn("CanvasManager导出图片失败:", error);
|
||||||
throw error;
|
throw error;
|
||||||
@@ -989,10 +1049,12 @@ export class CanvasManager {
|
|||||||
// 导出印花和元素图层信息
|
// 导出印花和元素图层信息
|
||||||
const printTrimsData = await this.exportPrintTrimsLayers().catch(() => ({prints: null, trims: null}));
|
const printTrimsData = await this.exportPrintTrimsLayers().catch(() => ({prints: null, trims: null}));
|
||||||
|
|
||||||
return {
|
const obj = {
|
||||||
color,
|
color,
|
||||||
...printTrimsData,
|
...printTrimsData,
|
||||||
};
|
};
|
||||||
|
console.log("==========exportExtraInfo:", obj);
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1533,7 +1595,7 @@ export class CanvasManager {
|
|||||||
selectable: true,
|
selectable: true,
|
||||||
hasControls: true,
|
hasControls: true,
|
||||||
hasBorders: true,
|
hasBorders: true,
|
||||||
specialType: SpecialType.PRINT_TRIMS_O,
|
isPrintTrims: true,
|
||||||
globalCompositeOperation: BlendMode.MULTIPLY,
|
globalCompositeOperation: BlendMode.MULTIPLY,
|
||||||
});
|
});
|
||||||
resolve(fabricImage);
|
resolve(fabricImage);
|
||||||
@@ -1547,7 +1609,7 @@ export class CanvasManager {
|
|||||||
visible: true,
|
visible: true,
|
||||||
locked: false,
|
locked: false,
|
||||||
opacity: 1.0,
|
opacity: 1.0,
|
||||||
specialType: SpecialType.PRINT_TRIMS_L,
|
isPrintTrims: true,
|
||||||
blendMode: BlendMode.MULTIPLY,
|
blendMode: BlendMode.MULTIPLY,
|
||||||
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
fabricObjects: [image.toObject(["id", "layerId", "layerName"])],
|
||||||
metadata: {sourceData: item},
|
metadata: {sourceData: item},
|
||||||
@@ -1571,37 +1633,57 @@ export class CanvasManager {
|
|||||||
resolve(tcanvas);
|
resolve(tcanvas);
|
||||||
}, { crossOrigin: "anonymous" });
|
}, { crossOrigin: "anonymous" });
|
||||||
})
|
})
|
||||||
let scaleX = fixedLayerObj.width / image.width * (item.scale?.[0] || 1) / 5;
|
let scaleX_ = fixedLayerObj.width / image.width * (item.scale?.[0] || 1) / 5;
|
||||||
let scaleY = fixedLayerObj.height / image.height * (item.scale?.[1] || 1) / 5;
|
let scaleY_ = fixedLayerObj.height / image.height * (item.scale?.[1] || 1) / 5;
|
||||||
let scale = fixedLayerObj.width > fixedLayerObj.height ? scaleX : scaleY;
|
let scale = fixedLayerObj.width > fixedLayerObj.height ? scaleX_ : scaleY_;
|
||||||
let left = (item.location?.[0] || 0) - image.width * scale / 2
|
let offsetX = (item.location?.[0] || 0) - image.width * scale / 2
|
||||||
let top = (item.location?.[1] || 0) - image.height * scale / 2
|
let offsetY = (item.location?.[1] || 0) - image.height * scale / 2
|
||||||
|
let top = fixedLayerObj.top - fixedLayerObj.height * fixedLayerObj.scaleY / 2
|
||||||
|
let left = fixedLayerObj.left - fixedLayerObj.width * fixedLayerObj.scaleX / 2
|
||||||
|
let scaleX = fixedLayerObj.scaleX
|
||||||
|
let scaleY = fixedLayerObj.scaleY
|
||||||
|
let opacity = 1
|
||||||
|
let angle = 0
|
||||||
|
let gapX = 0
|
||||||
|
let gapY = 0
|
||||||
|
let fillSource = image
|
||||||
|
if(item.object){
|
||||||
|
top += item.object.top * fixedLayerObj.scaleY
|
||||||
|
left += item.object.left * fixedLayerObj.scaleX
|
||||||
|
scaleX *= item.object.scaleX
|
||||||
|
scaleY *= item.object.scaleY
|
||||||
|
opacity = item.object.opacity
|
||||||
|
angle = item.object.angle
|
||||||
|
gapX = item.object.gapX
|
||||||
|
gapY = item.object.gapY
|
||||||
|
fillSource = imageAddGapToCanvas(image, gapX, gapY);
|
||||||
|
}
|
||||||
let rect = new fabric.Rect({
|
let rect = new fabric.Rect({
|
||||||
id: id,
|
id: id,
|
||||||
layerId: id,
|
layerId: id,
|
||||||
layerName: name,
|
layerName: name,
|
||||||
width: fixedLayerObj.width,
|
width: fixedLayerObj.width,
|
||||||
height: fixedLayerObj.height,
|
height: fixedLayerObj.height,
|
||||||
top: fixedLayerObj.top - fixedLayerObj.height * fixedLayerObj.scaleY / 2,
|
top: top,
|
||||||
left: fixedLayerObj.left - fixedLayerObj.width * fixedLayerObj.scaleX / 2,
|
left: left,
|
||||||
scaleX: fixedLayerObj.scaleX,
|
scaleX: scaleX,
|
||||||
scaleY: fixedLayerObj.scaleY,
|
scaleY: scaleY,
|
||||||
globalCompositeOperation: BlendMode.MULTIPLY,
|
globalCompositeOperation: BlendMode.MULTIPLY,
|
||||||
fill: new fabric.Pattern({
|
fill: new fabric.Pattern({
|
||||||
source: image,
|
source: fillSource,
|
||||||
repeat: "repeat",
|
repeat: "repeat",
|
||||||
patternTransform: createPatternTransform(scale, item.angle || 0),
|
patternTransform: createPatternTransform(scale, item.angle || 0),
|
||||||
offsetX: left, // 水平偏移
|
offsetX: offsetX, // 水平偏移
|
||||||
offsetY: top, // 垂直偏移
|
offsetY: offsetY, // 垂直偏移
|
||||||
}),
|
}),
|
||||||
fill_ : {
|
fill_ : {
|
||||||
source: item.path,
|
source: item.path,
|
||||||
gapX: 0,
|
gapX: gapX,
|
||||||
gapY: 0,
|
gapY: gapY,
|
||||||
width: image.width,
|
width: image.width,
|
||||||
height: image.height,
|
height: image.height,
|
||||||
},
|
},
|
||||||
specialType: SpecialType.REPEAT_O,
|
isPrintTrims: true,
|
||||||
});
|
});
|
||||||
this.canvas.add(rect);
|
this.canvas.add(rect);
|
||||||
let layer = createLayer({
|
let layer = createLayer({
|
||||||
@@ -1611,7 +1693,7 @@ export class CanvasManager {
|
|||||||
visible: true,
|
visible: true,
|
||||||
locked: true,
|
locked: true,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
specialType: SpecialType.REPEAT_L,
|
isPrintTrims: true,
|
||||||
blendMode: BlendMode.MULTIPLY,
|
blendMode: BlendMode.MULTIPLY,
|
||||||
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
fabricObjects: [rect.toObject(["id", "layerId", "layerName"])],
|
||||||
metadata: {sourceData: item},
|
metadata: {sourceData: item},
|
||||||
@@ -1630,7 +1712,7 @@ export class CanvasManager {
|
|||||||
// })
|
// })
|
||||||
// children.push(layer);
|
// children.push(layer);
|
||||||
// }
|
// }
|
||||||
// if(children.length === 0) return;
|
if(children.length === 0) return;
|
||||||
const groupRect = new fabric.Rect({});
|
const groupRect = new fabric.Rect({});
|
||||||
await this.setObjecCliptInfo(groupRect);
|
await this.setObjecCliptInfo(groupRect);
|
||||||
// 插入组图层
|
// 插入组图层
|
||||||
@@ -1646,11 +1728,8 @@ export class CanvasManager {
|
|||||||
children: children,
|
children: children,
|
||||||
clippingMask: groupRect.toObject(),
|
clippingMask: groupRect.toObject(),
|
||||||
isPrintTrimsGroup: true,
|
isPrintTrimsGroup: true,
|
||||||
specialType: SpecialType.PRINT_TRIMS_G,
|
|
||||||
});
|
});
|
||||||
this.layers.value.splice(groupIndex, 0, groupLayer);
|
this.layers.value.splice(groupIndex, 0, groupLayer);
|
||||||
console.log("==========layers", [...this.layers.value]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export class ExportManager {
|
|||||||
* @param {Boolean} options.isContainBg 是否包含背景图层
|
* @param {Boolean} options.isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} options.isContainFixed 是否包含固定图层
|
* @param {Boolean} options.isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} options.isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} options.isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Boolean} options.isCropByBg 是否使用背景大小裁剪
|
* @param {Boolean} options.isCropByBg 是否使用背景大小裁剪
|
||||||
* @param {String} options.layerId 导出具体图层ID
|
* @param {String} options.layerId 导出具体图层ID
|
||||||
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
* @param {Array} options.layerIdArray 导出多个图层ID数组
|
||||||
@@ -35,6 +36,7 @@ export class ExportManager {
|
|||||||
isContainBg = false,
|
isContainBg = false,
|
||||||
isContainFixed = false,
|
isContainFixed = false,
|
||||||
isContainFixedOther = false, // 是否包含其他固定图层
|
isContainFixedOther = false, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer = true, // 是否包含普通图层
|
||||||
isCropByBg = false, // 是否使用背景大小裁剪
|
isCropByBg = false, // 是否使用背景大小裁剪
|
||||||
layerId = "",
|
layerId = "",
|
||||||
layerIdArray = [],
|
layerIdArray = [],
|
||||||
@@ -68,6 +70,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg,
|
isCropByBg,
|
||||||
@@ -81,6 +84,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg,
|
isCropByBg,
|
||||||
@@ -160,6 +164,7 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
||||||
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
||||||
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
||||||
@@ -173,6 +178,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer = true, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg, // 是否使用背景大小裁剪
|
isCropByBg, // 是否使用背景大小裁剪
|
||||||
@@ -188,6 +194,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
);
|
);
|
||||||
|
|
||||||
if (objectsToExport.length === 0) {
|
if (objectsToExport.length === 0) {
|
||||||
@@ -220,6 +227,7 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
* @param {Boolean} isRedGreenMode 是否为红绿图模式
|
||||||
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
* @param {Boolean} restoreOpacityInRedGreen 红绿图模式下是否恢复透明度为1
|
||||||
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
* @param {Boolean} isCropByBg 是否使用背景大小裁剪
|
||||||
@@ -233,6 +241,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
isRedGreenMode,
|
isRedGreenMode,
|
||||||
restoreOpacityInRedGreen,
|
restoreOpacityInRedGreen,
|
||||||
isCropByBg, // 是否使用背景大小裁剪
|
isCropByBg, // 是否使用背景大小裁剪
|
||||||
@@ -246,6 +255,7 @@ export class ExportManager {
|
|||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
isContainFixedOther, // 是否包含其他固定图层
|
isContainFixedOther, // 是否包含其他固定图层
|
||||||
|
isContainNormalLayer, // 是否包含普通图层
|
||||||
excludedLayers,
|
excludedLayers,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -405,11 +415,12 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @param {Array} excludedLayers 排除的图层ID数组
|
* @param {Array} excludedLayers 排除的图层ID数组
|
||||||
* @returns {Array} 按正确顺序排列的真实对象数组
|
* @returns {Array} 按正确顺序排列的真实对象数组
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_collectObjectsByLayerOrder(layerIdArray, isContainBg, isContainFixed, isContainFixedOther, excludedLayers) {
|
_collectObjectsByLayerOrder(layerIdArray, isContainBg, isContainFixed, isContainFixedOther, isContainNormalLayer, excludedLayers) {
|
||||||
const objectsToExport = [];
|
const objectsToExport = [];
|
||||||
const allLayers = this._getAllLayersFlattened(excludedLayers); // 获取扁平化的图层列表
|
const allLayers = this._getAllLayersFlattened(excludedLayers); // 获取扁平化的图层列表
|
||||||
|
|
||||||
@@ -421,7 +432,7 @@ export class ExportManager {
|
|||||||
if (layerIdArray && !layerIdArray.includes(layer.id)) continue;
|
if (layerIdArray && !layerIdArray.includes(layer.id)) continue;
|
||||||
|
|
||||||
// 检查图层类型过滤条件
|
// 检查图层类型过滤条件
|
||||||
if (!this._shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther))
|
if (!this._shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther, isContainNormalLayer))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (layer.visible) {
|
if (layer.visible) {
|
||||||
@@ -1040,10 +1051,11 @@ export class ExportManager {
|
|||||||
* @param {Boolean} isContainBg 是否包含背景图层
|
* @param {Boolean} isContainBg 是否包含背景图层
|
||||||
* @param {Boolean} isContainFixed 是否包含固定图层
|
* @param {Boolean} isContainFixed 是否包含固定图层
|
||||||
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
* @param {Boolean} isContainFixedOther 是否包含其他固定图层
|
||||||
|
* @param {Boolean} isContainNormalLayer 是否包含普通图层
|
||||||
* @returns {Boolean} 是否应该包含
|
* @returns {Boolean} 是否应该包含
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther) {
|
_shouldIncludeLayer(layer, isContainBg, isContainFixed, isContainFixedOther, isContainNormalLayer) {
|
||||||
if (!layer) return false;
|
if (!layer) return false;
|
||||||
|
|
||||||
// 检查背景图层
|
// 检查背景图层
|
||||||
@@ -1061,7 +1073,12 @@ export class ExportManager {
|
|||||||
return isContainFixedOther;
|
return isContainFixedOther;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 普通图层总是包含
|
// 印花图层始终导出
|
||||||
return true;
|
if (layer.isPrintTrims || layer.isPrintTrimsGroup) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 普通图层
|
||||||
|
return isContainNormalLayer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
325
src/component/Canvas/CanvasEditor/managers/PartManager.js
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
import { fabric } from "fabric-with-all";
|
||||||
|
import { generateId } from "../utils/helper";
|
||||||
|
import { OperationType } from "../utils/layerHelper";
|
||||||
|
import { CreateSelectionCommand } from "../commands/SelectionCommands";
|
||||||
|
import { ClearSelectionCommand } from "../commands/LassoCutoutCommand";
|
||||||
|
import addIcon from "@/assets/images/canvas/add.png";
|
||||||
|
import removeIcon from "@/assets/images/canvas/remove.png";
|
||||||
|
import { Https } from "@/tool/https";
|
||||||
|
import store from "@/store";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部件选择管理器
|
||||||
|
*/
|
||||||
|
export class PartManager {
|
||||||
|
/**
|
||||||
|
* 创建部件选择管理器
|
||||||
|
* @param {Object} options 配置选项
|
||||||
|
* @param {Object} options.canvas fabric.js画布实例
|
||||||
|
* @param {Object} options.commandManager 命令管理器实例
|
||||||
|
* @param {Object} options.canvasManager 画布管理实例
|
||||||
|
* @param {Object} options.layerManager 图层管理实例
|
||||||
|
* @param {Object} options.toolManager 工具管理实例
|
||||||
|
*/
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.canvas = options.canvas;
|
||||||
|
this.commandManager = options.commandManager;
|
||||||
|
this.layerManager = options.layerManager;
|
||||||
|
this.canvasManager = options.canvasManager;
|
||||||
|
this.toolManager = options.toolManager;
|
||||||
|
this.props = options.props;
|
||||||
|
|
||||||
|
// 状态
|
||||||
|
this.isActive = false;
|
||||||
|
this.partObject = null; // 当前选区对象
|
||||||
|
this.partId = "part_selector";
|
||||||
|
this.defaultCursor = "default";
|
||||||
|
|
||||||
|
// 绘制状态
|
||||||
|
this.drawingObject = null;
|
||||||
|
this.startPoint = null;
|
||||||
|
this.partPath = null; // 存储选区路径数据
|
||||||
|
|
||||||
|
|
||||||
|
// 不再直接绑定事件处理函数
|
||||||
|
this._mouseDownHandler = null;
|
||||||
|
this._mouseMoveHandler = null;
|
||||||
|
this._mouseUpHandler = null;
|
||||||
|
this._keyDownHandler = null;
|
||||||
|
|
||||||
|
// 选区相关的工具类型
|
||||||
|
this.tools = [
|
||||||
|
OperationType.PART,
|
||||||
|
OperationType.PART_RECTANGLE,
|
||||||
|
OperationType.PART_BRUSH,
|
||||||
|
OperationType.PART_ERASER,
|
||||||
|
];
|
||||||
|
|
||||||
|
// 当前工具
|
||||||
|
this.activeTool = this.toolManager.activeTool;
|
||||||
|
|
||||||
|
// 选区状态变化回调
|
||||||
|
this.onSelectionChanged = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前工具
|
||||||
|
* @param {String} toolId 工具ID
|
||||||
|
*/
|
||||||
|
setCurrentTool(toolId) {
|
||||||
|
// 检查是否为选区工具
|
||||||
|
const wasActive = this.isActive;
|
||||||
|
this.isActive = this.tools.includes(toolId);
|
||||||
|
|
||||||
|
// 如果从非选区工具切换到选区工具,初始化事件
|
||||||
|
if (!wasActive && this.isActive) {
|
||||||
|
this.initEvents();
|
||||||
|
}
|
||||||
|
// 如果从选区工具切换到非选区工具,清理事件和选区
|
||||||
|
else if (wasActive && !this.isActive) {
|
||||||
|
this.cleanupEvents();
|
||||||
|
this.clearSelection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化选区相关事件
|
||||||
|
*/
|
||||||
|
initEvents() {
|
||||||
|
if (!this.canvas || this._mouseDownHandler) return; // 避免重复初始化
|
||||||
|
this.defaultCursor = this.canvas.defaultCursor;
|
||||||
|
|
||||||
|
// 保存实例引用,用于事件处理函数中
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
// 鼠标按下事件处理
|
||||||
|
this._mouseDownHandler = (options) => {
|
||||||
|
// 如果选区功能未激活,不处理事件
|
||||||
|
if (!this.isActive) return;
|
||||||
|
// 阻止事件冒泡,避免与 CanvasEventManager 冲突
|
||||||
|
options.e.stopPropagation();
|
||||||
|
switch (this.activeTool.value) {
|
||||||
|
case OperationType.PART:
|
||||||
|
this._pointDownkHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_RECTANGLE:
|
||||||
|
this._rectangleDownHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_BRUSH:
|
||||||
|
this._brushDownHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_ERASER:
|
||||||
|
this._eraseDownHandler(options);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 鼠标移动事件处理
|
||||||
|
this._mouseMoveHandler = (options) => {
|
||||||
|
// 如果选区功能未激活或没有正在绘制的对象,不处理事件
|
||||||
|
if (!this.isActive) return;
|
||||||
|
// 阻止事件冒泡
|
||||||
|
options.e.stopPropagation();
|
||||||
|
switch (this.activeTool.value) {
|
||||||
|
case OperationType.PART:
|
||||||
|
this._pointMoveHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_RECTANGLE:
|
||||||
|
this._rectangleMoveHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_BRUSH:
|
||||||
|
this._brushMoveHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_ERASER:
|
||||||
|
this._eraseMoveHandler(options);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 鼠标抬起事件处理
|
||||||
|
this._mouseUpHandler = (options) => {
|
||||||
|
// 如果选区功能未激活或没有正在绘制的对象,不处理事件
|
||||||
|
if (!this.isActive) return;
|
||||||
|
// 阻止事件冒泡
|
||||||
|
if (options && options.e) {
|
||||||
|
options.e.stopPropagation();
|
||||||
|
}
|
||||||
|
switch (this.activeTool.value) {
|
||||||
|
case OperationType.PART:
|
||||||
|
this._pointUpHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_RECTANGLE:
|
||||||
|
this._rectangleUpHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_BRUSH:
|
||||||
|
this._brushUpHandler(options);
|
||||||
|
break;
|
||||||
|
case OperationType.PART_ERASER:
|
||||||
|
this._eraseUpHandler(options);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 键盘事件处理
|
||||||
|
this._keyDownHandler = (event) => {
|
||||||
|
// 只在选区功能激活时处理键盘事件
|
||||||
|
if (!this.isActive) return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加事件监听
|
||||||
|
this.canvas.on("mouse:down", this._mouseDownHandler);
|
||||||
|
this.canvas.on("mouse:move", this._mouseMoveHandler);
|
||||||
|
this.canvas.on("mouse:up", this._mouseUpHandler);
|
||||||
|
|
||||||
|
// 添加键盘事件监听
|
||||||
|
document.addEventListener("keydown", this._keyDownHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理事件监听
|
||||||
|
*/
|
||||||
|
cleanupEvents() {
|
||||||
|
if (!this.canvas) return;
|
||||||
|
|
||||||
|
// 移除事件监听
|
||||||
|
if (this._mouseDownHandler) {
|
||||||
|
this.canvas.off("mouse:down", this._mouseDownHandler);
|
||||||
|
this._mouseDownHandler = null;
|
||||||
|
}
|
||||||
|
if (this._mouseMoveHandler) {
|
||||||
|
this.canvas.off("mouse:move", this._mouseMoveHandler);
|
||||||
|
this._mouseMoveHandler = null;
|
||||||
|
}
|
||||||
|
if (this._mouseUpHandler) {
|
||||||
|
this.canvas.off("mouse:up", this._mouseUpHandler);
|
||||||
|
this._mouseUpHandler = null;
|
||||||
|
}
|
||||||
|
if (this._keyDownHandler) {
|
||||||
|
document.removeEventListener("keydown", this._keyDownHandler);
|
||||||
|
this._keyDownHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点选工具模式下点击事件处理
|
||||||
|
_pointDownkHandler(options) {
|
||||||
|
const button = options.button;
|
||||||
|
const isLeft = button === 1;// 左键1(添加) 右键3(删除)
|
||||||
|
const icon = `url("${isLeft ? addIcon : removeIcon}") 16 16, default`
|
||||||
|
this.canvas.upperCanvasEl.style.cursor = icon;
|
||||||
|
}
|
||||||
|
// 点选工具模式下移动事件处理
|
||||||
|
_pointMoveHandler(options) { }
|
||||||
|
// 点选工具模式下抬起事件处理
|
||||||
|
_pointUpHandler(options) {
|
||||||
|
const button = options.button;
|
||||||
|
const isLeft = button === 1;// 左键1(添加) 右键3(删除)
|
||||||
|
this.canvas.upperCanvasEl.style.cursor = this.defaultCursor;
|
||||||
|
const fixedObject = this.canvasManager.getFixedLayerObject();
|
||||||
|
if (!fixedObject) return console.warn("未找到固定图层");
|
||||||
|
const { x, y } = options.pointer;
|
||||||
|
const width = fixedObject.width * fixedObject.scaleX;
|
||||||
|
const height = fixedObject.height * fixedObject.scaleY;
|
||||||
|
const X = x - (fixedObject.left - width / 2);
|
||||||
|
const Y = y - (fixedObject.top - height / 2);
|
||||||
|
this.getSegAnythingImage({
|
||||||
|
image_path: "aida-users/24299/sketch/70bb39cc-63e0-44a9-a627-3542d0f9cd70.png",
|
||||||
|
type: "point",
|
||||||
|
points: [[X, Y], [X - 10, Y - 10]],
|
||||||
|
labels: [1, 0],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 框选工具模式下点击事件处理
|
||||||
|
_rectangleDownHandler(options) {
|
||||||
|
}
|
||||||
|
// 框选工具模式下移动事件处理
|
||||||
|
_rectangleMoveHandler(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
// 框选工具模式下抬起事件处理
|
||||||
|
_rectangleUpHandler(options) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 绘制工具模式下点击事件处理
|
||||||
|
_brushDownHandler(options) {
|
||||||
|
}
|
||||||
|
// 绘制工具模式下移动事件处理
|
||||||
|
_brushMoveHandler(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
// 绘制工具模式下抬起事件处理
|
||||||
|
_brushUpHandler(options) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 擦除工具模式下抬起事件处理
|
||||||
|
_eraseUpHandler(options) {
|
||||||
|
}
|
||||||
|
// 擦除工具模式下点击事件处理
|
||||||
|
_eraseDownHandler(options) {
|
||||||
|
}
|
||||||
|
// 擦除工具模式下移动事件处理
|
||||||
|
_eraseMoveHandler(options) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 获取分隔后图片
|
||||||
|
async getSegAnythingImage(obj) {
|
||||||
|
const user_id = store.state.UserHabit.userDetail.userId;
|
||||||
|
const data = {
|
||||||
|
user_id,
|
||||||
|
...obj,
|
||||||
|
}
|
||||||
|
Https.axiosPost(Https.httpUrls.segAnything, data)
|
||||||
|
.then(response => {
|
||||||
|
console.log(response);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除选区
|
||||||
|
*/
|
||||||
|
clearSelection() {
|
||||||
|
// 移除选区对象
|
||||||
|
// this.removeSelectionFromCanvas();
|
||||||
|
|
||||||
|
// 重置选区状态
|
||||||
|
this.partObject = null;
|
||||||
|
this.partPath = null;
|
||||||
|
|
||||||
|
// 触发选区变化回调
|
||||||
|
if (this.onSelectionChanged && typeof this.onSelectionChanged === "function") {
|
||||||
|
this.onSelectionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理资源
|
||||||
|
*/
|
||||||
|
dispose() {
|
||||||
|
this.cleanupEvents();
|
||||||
|
this.clearSelection();
|
||||||
|
this.canvas = null;
|
||||||
|
this.commandManager = null;
|
||||||
|
this.layerManager = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ export class ToolManager {
|
|||||||
this.activeTool = options.activeTool || {
|
this.activeTool = options.activeTool || {
|
||||||
value: OperationType.SELECT,
|
value: OperationType.SELECT,
|
||||||
};
|
};
|
||||||
|
this.props = options.props;
|
||||||
|
|
||||||
// 红绿图模式状态
|
// 红绿图模式状态
|
||||||
this.isRedGreenMode = false;
|
this.isRedGreenMode = false;
|
||||||
@@ -67,6 +68,12 @@ export class ToolManager {
|
|||||||
|
|
||||||
// 工具列表 - 与OperationType保持一致
|
// 工具列表 - 与OperationType保持一致
|
||||||
this.tools = {
|
this.tools = {
|
||||||
|
// 禁用工具
|
||||||
|
[OperationType.DISABLED]: {
|
||||||
|
name: "禁用工具",
|
||||||
|
icon: "disabled",
|
||||||
|
cursor: "not-allowed",
|
||||||
|
},
|
||||||
// 基础工具
|
// 基础工具
|
||||||
[OperationType.SELECT]: {
|
[OperationType.SELECT]: {
|
||||||
name: "选择工具",
|
name: "选择工具",
|
||||||
@@ -83,6 +90,7 @@ export class ToolManager {
|
|||||||
shortcut: "B",
|
shortcut: "B",
|
||||||
setup: this.setupBrushTool.bind(this),
|
setup: this.setupBrushTool.bind(this),
|
||||||
allowedInRedGreen: false,
|
allowedInRedGreen: false,
|
||||||
|
specialLayerDisabled: true,
|
||||||
},
|
},
|
||||||
[OperationType.ERASER]: {
|
[OperationType.ERASER]: {
|
||||||
name: "橡皮擦",
|
name: "橡皮擦",
|
||||||
@@ -91,6 +99,7 @@ export class ToolManager {
|
|||||||
shortcut: "E",
|
shortcut: "E",
|
||||||
setup: this.setupEraserTool.bind(this),
|
setup: this.setupEraserTool.bind(this),
|
||||||
allowedInRedGreen: true, // 红绿图模式允许橡皮擦
|
allowedInRedGreen: true, // 红绿图模式允许橡皮擦
|
||||||
|
specialLayerDisabled: true,
|
||||||
},
|
},
|
||||||
[OperationType.EYEDROPPER]: {
|
[OperationType.EYEDROPPER]: {
|
||||||
name: "吸色工具",
|
name: "吸色工具",
|
||||||
@@ -117,6 +126,7 @@ export class ToolManager {
|
|||||||
shortcut: "L",
|
shortcut: "L",
|
||||||
setup: this.setupLassoTool.bind(this),
|
setup: this.setupLassoTool.bind(this),
|
||||||
allowedInRedGreen: false,
|
allowedInRedGreen: false,
|
||||||
|
specialLayerDisabled: true,
|
||||||
},
|
},
|
||||||
[OperationType.LASSO_RECTANGLE]: {
|
[OperationType.LASSO_RECTANGLE]: {
|
||||||
name: "矩形套索工具",
|
name: "矩形套索工具",
|
||||||
@@ -126,6 +136,7 @@ export class ToolManager {
|
|||||||
altKey: true,
|
altKey: true,
|
||||||
setup: this.setupRectangleLassoTool.bind(this),
|
setup: this.setupRectangleLassoTool.bind(this),
|
||||||
allowedInRedGreen: false,
|
allowedInRedGreen: false,
|
||||||
|
specialLayerDisabled: true,
|
||||||
},
|
},
|
||||||
[OperationType.LASSO_ELLIPSE]: {
|
[OperationType.LASSO_ELLIPSE]: {
|
||||||
name: "椭圆形套索工具",
|
name: "椭圆形套索工具",
|
||||||
@@ -135,6 +146,7 @@ export class ToolManager {
|
|||||||
altKey: true,
|
altKey: true,
|
||||||
setup: this.setupEllipseLassoTool.bind(this),
|
setup: this.setupEllipseLassoTool.bind(this),
|
||||||
allowedInRedGreen: false,
|
allowedInRedGreen: false,
|
||||||
|
specialLayerDisabled: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 选区工具 - 只需要矩形选区
|
// 选区工具 - 只需要矩形选区
|
||||||
@@ -164,6 +176,7 @@ export class ToolManager {
|
|||||||
shortcut: "J",
|
shortcut: "J",
|
||||||
setup: this.setupLiquifyTool.bind(this),
|
setup: this.setupLiquifyTool.bind(this),
|
||||||
allowedInRedGreen: false, // 红绿图模式不允许液化
|
allowedInRedGreen: false, // 红绿图模式不允许液化
|
||||||
|
specialLayerDisabled: true,
|
||||||
},
|
},
|
||||||
[OperationType.TEXT]: {
|
[OperationType.TEXT]: {
|
||||||
name: "文本工具",
|
name: "文本工具",
|
||||||
@@ -174,6 +187,32 @@ export class ToolManager {
|
|||||||
allowedInRedGreen: false, // 红绿图模式不允许文本
|
allowedInRedGreen: false, // 红绿图模式不允许文本
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 部件选取工具
|
||||||
|
[OperationType.PART]: {
|
||||||
|
name: "部件选取工具",
|
||||||
|
icon: "part",
|
||||||
|
cursor: "default",
|
||||||
|
setup: this.setupPartTool.bind(this),
|
||||||
|
},
|
||||||
|
[OperationType.PART_RECTANGLE]: {
|
||||||
|
name: "部件选取工具-矩形",
|
||||||
|
icon: "part",
|
||||||
|
cursor: "default",
|
||||||
|
setup: this.setupPartRectangleTool.bind(this),
|
||||||
|
},
|
||||||
|
[OperationType.PART_BRUSH]: {
|
||||||
|
name: "部件选取工具-画笔",
|
||||||
|
icon: "part",
|
||||||
|
cursor: "default",
|
||||||
|
setup: this.setupPartBrushTool.bind(this),
|
||||||
|
},
|
||||||
|
[OperationType.PART_ERASER]: {
|
||||||
|
name: "部件选取工具-橡皮擦",
|
||||||
|
icon: "part",
|
||||||
|
cursor: "default",
|
||||||
|
setup: this.setupPartEraserTool.bind(this),
|
||||||
|
},
|
||||||
|
|
||||||
// 红绿图模式专用工具
|
// 红绿图模式专用工具
|
||||||
[OperationType.RED_BRUSH]: {
|
[OperationType.RED_BRUSH]: {
|
||||||
name: "红色笔刷",
|
name: "红色笔刷",
|
||||||
@@ -331,8 +370,9 @@ export class ToolManager {
|
|||||||
* @param {String} toolId 工具ID
|
* @param {String} toolId 工具ID
|
||||||
*/
|
*/
|
||||||
setTool(toolId) {
|
setTool(toolId) {
|
||||||
|
const tool = this.tools[toolId];
|
||||||
// 检查工具是否存在
|
// 检查工具是否存在
|
||||||
if (!this.tools[toolId]) {
|
if (!tool) {
|
||||||
console.error(`工具 '${toolId}' 不存在`);
|
console.error(`工具 '${toolId}' 不存在`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -348,15 +388,20 @@ export class ToolManager {
|
|||||||
console.warn(`工具 '${toolId}' 只能在红绿图模式下使用`);
|
console.warn(`工具 '${toolId}' 只能在红绿图模式下使用`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(tool?.specialLayerDisabled && this.checkToolCanOperateSelectedObject()){
|
||||||
|
console.warn(`工具 '${toolId}' 不能在当前选中对象上操作`);
|
||||||
|
toolId = OperationType.DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
// 保存先前的工具
|
// 保存先前的工具
|
||||||
this.previousTool = this.activeTool.value;
|
this.previousTool = this.activeTool.value;
|
||||||
|
|
||||||
// 取消画布的选中状态
|
// 取消画布的选中状态
|
||||||
this.canvas?.discardActiveObject();
|
if(toolId !== OperationType.DISABLED){
|
||||||
this.canvasManager?.layerManager?.updateLayersObjectsInteractivity?.();
|
this.canvas?.discardActiveObject();
|
||||||
this.canvas?.renderAll();
|
this.canvasManager?.layerManager?.updateLayersObjectsInteractivity?.();
|
||||||
|
this.canvas?.renderAll();
|
||||||
|
}
|
||||||
// 隐藏文本编辑面板
|
// 隐藏文本编辑面板
|
||||||
this.hideTextEditor();
|
this.hideTextEditor();
|
||||||
|
|
||||||
@@ -374,7 +419,6 @@ export class ToolManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设置工具特定的状态
|
// 设置工具特定的状态
|
||||||
const tool = this.tools[toolId];
|
|
||||||
if (tool && typeof tool.setup === "function") {
|
if (tool && typeof tool.setup === "function") {
|
||||||
console.log(`画布切换工具:${tool.name}(${toolId})`)
|
console.log(`画布切换工具:${tool.name}(${toolId})`)
|
||||||
this.canvas.toolId = toolId;
|
this.canvas.toolId = toolId;
|
||||||
@@ -424,7 +468,7 @@ export class ToolManager {
|
|||||||
|
|
||||||
const currentTool = this.activeTool.value;
|
const currentTool = this.activeTool.value;
|
||||||
const tool = this.tools[currentTool];
|
const tool = this.tools[currentTool];
|
||||||
|
if(tool?.specialLayerDisabled && this.checkToolCanOperateSelectedObject()) return;
|
||||||
// 根据当前工具设置selection状态
|
// 根据当前工具设置selection状态
|
||||||
if (currentTool === OperationType.SELECT) {
|
if (currentTool === OperationType.SELECT) {
|
||||||
this.canvas.selection = true;
|
this.canvas.selection = true;
|
||||||
@@ -455,24 +499,19 @@ export class ToolManager {
|
|||||||
if (!this.canvas) return;
|
if (!this.canvas) return;
|
||||||
this.canvas.isDrawingMode = false;
|
this.canvas.isDrawingMode = false;
|
||||||
this.canvas.selection = true;
|
this.canvas.selection = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查当前工具是否禁止操作当前选中的对象
|
* 检查当前工具是否禁止操作当前选中的对象
|
||||||
* @param {Boolean} isBrushTool 是否为画笔工具
|
|
||||||
* @returns {Boolean} 是否可以切换
|
* @returns {Boolean} 是否可以切换
|
||||||
*/
|
*/
|
||||||
checkToolCanOperateSelectedObject(isBrushTool = false) {
|
checkToolCanOperateSelectedObject() {
|
||||||
const layer = this.layerManager?.getActiveLayer();
|
const layer = this.layerManager?.getActiveLayer();
|
||||||
const isSpecialLayer = !!layer?.specialType;
|
const isSpecialLayer = !!layer?.isPrintTrims || !!layer?.isPrintTrimsGroup;
|
||||||
if (isSpecialLayer) {
|
if (isSpecialLayer) {
|
||||||
if(isBrushTool){
|
this._disableBrushIndicator();
|
||||||
this._disableBrushIndicator();
|
|
||||||
}
|
|
||||||
this.canvas.defaultCursor = "not-allowed";
|
this.canvas.defaultCursor = "not-allowed";
|
||||||
}
|
}
|
||||||
console.log("===========",isSpecialLayer, this.canvas.defaultCursor);
|
|
||||||
return isSpecialLayer;
|
return isSpecialLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +521,7 @@ export class ToolManager {
|
|||||||
*/
|
*/
|
||||||
setupBrushTool() {
|
setupBrushTool() {
|
||||||
if (!this.canvas) return;
|
if (!this.canvas) return;
|
||||||
if (this.checkToolCanOperateSelectedObject(true)) return;
|
if (this.checkToolCanOperateSelectedObject()) return;
|
||||||
|
|
||||||
this.canvas.isDrawingMode = true;
|
this.canvas.isDrawingMode = true;
|
||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
@@ -526,7 +565,7 @@ export class ToolManager {
|
|||||||
*/
|
*/
|
||||||
setupEraserTool() {
|
setupEraserTool() {
|
||||||
if (!this.canvas) return;
|
if (!this.canvas) return;
|
||||||
if (this.checkToolCanOperateSelectedObject(true)) return;
|
if (this.checkToolCanOperateSelectedObject()) return;
|
||||||
|
|
||||||
this.canvas.isDrawingMode = true;
|
this.canvas.isDrawingMode = true;
|
||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
@@ -580,6 +619,7 @@ export class ToolManager {
|
|||||||
*/
|
*/
|
||||||
setupLassoTool() {
|
setupLassoTool() {
|
||||||
if (!this.canvas) return;
|
if (!this.canvas) return;
|
||||||
|
if (this.checkToolCanOperateSelectedObject()) return;
|
||||||
|
|
||||||
this.canvas.isDrawingMode = false;
|
this.canvas.isDrawingMode = false;
|
||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
@@ -661,6 +701,53 @@ export class ToolManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置部件选取工具
|
||||||
|
*/
|
||||||
|
setupPartTool() {
|
||||||
|
if (!this.canvas) return;
|
||||||
|
this.canvas.isDrawingMode = false;
|
||||||
|
this.canvas.selection = false;
|
||||||
|
|
||||||
|
if (this.canvasManager && this.canvasManager.partManager) {
|
||||||
|
this.canvasManager.partManager.setCurrentTool(OperationType.PART);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置部件选取工具--矩形
|
||||||
|
*/
|
||||||
|
setupPartRectangleTool() {
|
||||||
|
if (!this.canvas) return;
|
||||||
|
this.canvas.isDrawingMode = false;
|
||||||
|
this.canvas.selection = true;
|
||||||
|
if (this.canvasManager && this.canvasManager.partManager) {
|
||||||
|
this.canvasManager.partManager.setCurrentTool(OperationType.PART_RECTANGLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置部件选取工具--画笔
|
||||||
|
*/
|
||||||
|
setupPartBrushTool() {
|
||||||
|
if (!this.canvas) return;
|
||||||
|
this.canvas.isDrawingMode = true;
|
||||||
|
this.canvas.selection = false;
|
||||||
|
if (this.canvasManager && this.canvasManager.partManager) {
|
||||||
|
this.canvasManager.partManager.setCurrentTool(OperationType.PART_BRUSH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 设置部件选取工具--橡皮擦
|
||||||
|
*/
|
||||||
|
setupPartEraserTool() {
|
||||||
|
if (!this.canvas) return;
|
||||||
|
this.canvas.isDrawingMode = false;
|
||||||
|
this.canvas.selection = false;
|
||||||
|
if (this.canvasManager && this.canvasManager.partManager) {
|
||||||
|
this.canvasManager.partManager.setCurrentTool(OperationType.PART_ERASER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置波浪工具
|
* 设置波浪工具
|
||||||
*/
|
*/
|
||||||
@@ -676,7 +763,7 @@ export class ToolManager {
|
|||||||
*/
|
*/
|
||||||
setupLiquifyTool() {
|
setupLiquifyTool() {
|
||||||
if (!this.canvas || !this.layerManager) return;
|
if (!this.canvas || !this.layerManager) return;
|
||||||
if (this.checkToolCanOperateSelectedObject(true)) return;
|
if (this.checkToolCanOperateSelectedObject()) return;
|
||||||
|
|
||||||
this.canvas.isDrawingMode = false;
|
this.canvas.isDrawingMode = false;
|
||||||
this.canvas.selection = false;
|
this.canvas.selection = false;
|
||||||
|
|||||||
@@ -1005,3 +1005,110 @@ export async function base64ToCanvas(base64, scale = 1, sr = false) {
|
|||||||
image.onerror = reject;
|
image.onerror = reject;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片边界跟踪算法(透明底)
|
||||||
|
* @param {HTMLCanvasElement} canvas - canvas元素
|
||||||
|
* @returns {Array} 边界点数组 [{x, y}, ...]
|
||||||
|
*/
|
||||||
|
export function traceImageContour(canvas) {
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
const data = imageData.data;
|
||||||
|
const width = canvas.width;
|
||||||
|
const height = canvas.height;
|
||||||
|
|
||||||
|
// 查找起始点(第一个不透明像素)
|
||||||
|
let startX = -1;
|
||||||
|
let startY = -1;
|
||||||
|
|
||||||
|
outer: for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
const index = (y * width + x) * 4;
|
||||||
|
if (data[index + 3] > 0) {
|
||||||
|
startX = x;
|
||||||
|
startY = y;
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startX === -1) return []; // 没有不透明像素
|
||||||
|
|
||||||
|
// Moore-Neighbor边界跟踪算法
|
||||||
|
const contour = [];
|
||||||
|
const visited = new Set();
|
||||||
|
const directions = [
|
||||||
|
[-1, 0],
|
||||||
|
[-1, -1],
|
||||||
|
[0, -1],
|
||||||
|
[1, -1],
|
||||||
|
[1, 0],
|
||||||
|
[1, 1],
|
||||||
|
[0, 1],
|
||||||
|
[-1, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
let currentX = startX;
|
||||||
|
let currentY = startY;
|
||||||
|
let backtrackDir = 4; // 起始方向:右
|
||||||
|
|
||||||
|
do {
|
||||||
|
const pointKey = `${currentX},${currentY}`;
|
||||||
|
if (!visited.has(pointKey)) {
|
||||||
|
contour.push({ x: currentX, y: currentY });
|
||||||
|
visited.add(pointKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从右方向开始顺时针查找
|
||||||
|
let found = false;
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const dir = (backtrackDir + i) % 8;
|
||||||
|
const dx = directions[dir][0];
|
||||||
|
const dy = directions[dir][1];
|
||||||
|
const checkX = currentX + dx;
|
||||||
|
const checkY = currentY + dy;
|
||||||
|
|
||||||
|
if (
|
||||||
|
checkX >= 0 &&
|
||||||
|
checkX < width &&
|
||||||
|
checkY >= 0 &&
|
||||||
|
checkY < height
|
||||||
|
) {
|
||||||
|
const index = (checkY * width + checkX) * 4;
|
||||||
|
if (data[index + 3] > 0) {
|
||||||
|
currentX = checkX;
|
||||||
|
currentY = checkY;
|
||||||
|
backtrackDir = (dir + 5) % 8; // 下一个开始查找的方向
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) break;
|
||||||
|
} while (
|
||||||
|
!(currentX === startX && currentY === startY) &&
|
||||||
|
visited.size < width * height
|
||||||
|
);
|
||||||
|
|
||||||
|
return contour;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片添加gap转换
|
||||||
|
* @param {HTMLCanvasElement} image - img元素
|
||||||
|
* @param {Number} gapX - 水平gap
|
||||||
|
* @param {Number} gapY - 垂直gap
|
||||||
|
* @returns {HTMLCanvasElement} 转换后的canvas元素
|
||||||
|
*/
|
||||||
|
export function imageAddGapToCanvas(image, gapX, gapY) {
|
||||||
|
// 创建透明 Canvas
|
||||||
|
const tcanvas = document.createElement('canvas');
|
||||||
|
tcanvas.width = image.width + gapX;
|
||||||
|
tcanvas.height = image.height + gapY;
|
||||||
|
const ctx = tcanvas.getContext('2d');
|
||||||
|
ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
return tcanvas;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2191,3 +2191,27 @@ export const imageModeHandler = ({ imageMode, newImage, canvasWidth, canvasHeigh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调整图像大小
|
||||||
|
* @param {string} base64 - 原始base64字符串
|
||||||
|
* @param {number} width - 目标宽度
|
||||||
|
* @param {number} height - 目标高度
|
||||||
|
* @returns {Promise<string>} 处理后的base64字符串
|
||||||
|
*/
|
||||||
|
export const resizeImage = async (base64, width, height) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = base64;
|
||||||
|
img.onload = () => {
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.drawImage(img, 0, 0, width, height);
|
||||||
|
resolve(canvas.toDataURL());
|
||||||
|
};
|
||||||
|
img.onerror = reject;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -25,18 +25,6 @@ export const SpecialLayerId = {
|
|||||||
SPECIAL_GROUP: "group_special", // 特殊组
|
SPECIAL_GROUP: "group_special", // 特殊组
|
||||||
COLOR: "special_color", // 颜色图层
|
COLOR: "special_color", // 颜色图层
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 特殊类型
|
|
||||||
*/
|
|
||||||
export const SpecialType = {
|
|
||||||
PRINT_TRIMS_G: "print_trims_group", // 印花和元素图层组
|
|
||||||
PRINT_TRIMS_L: "print_trims_layer", // 印花和元素图层
|
|
||||||
PRINT_TRIMS_O: "print_trims_object", // 印花和元素图层对象
|
|
||||||
REPEAT_L: "repeat_layer",// 平铺图层
|
|
||||||
REPEAT_O: "repeat_object",// 平铺图层对象
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,6 +32,7 @@ export const SpecialType = {
|
|||||||
*/
|
*/
|
||||||
export const OperationType = {
|
export const OperationType = {
|
||||||
// 编辑器模式
|
// 编辑器模式
|
||||||
|
DISABLED: "disabled", // 禁用
|
||||||
DRAW: "draw", // 绘画模式
|
DRAW: "draw", // 绘画模式
|
||||||
ERASER: "eraser", // 橡皮擦模式
|
ERASER: "eraser", // 橡皮擦模式
|
||||||
SELECT: "select", // 选择模式
|
SELECT: "select", // 选择模式
|
||||||
@@ -76,6 +65,12 @@ export const OperationType = {
|
|||||||
RED_BRUSH: "red_brush", // 红色笔刷
|
RED_BRUSH: "red_brush", // 红色笔刷
|
||||||
GREEN_BRUSH: "green_brush", // 绿色笔刷
|
GREEN_BRUSH: "green_brush", // 绿色笔刷
|
||||||
|
|
||||||
|
// 部件选取工具
|
||||||
|
PART: "part", // 部件选取工具模式 - 点选模式
|
||||||
|
PART_RECTANGLE: "part_rectangle", // 部件选取工具模式 - 矩形模式
|
||||||
|
PART_BRUSH: "part_brush", // 部件选取工具模式 - 笔刷模式
|
||||||
|
PART_ERASER: "part_eraser", // 部件选取工具模式 - 橡皮擦模式
|
||||||
|
|
||||||
// SHAPE: "shape", // 形状模式
|
// SHAPE: "shape", // 形状模式
|
||||||
// 可以根据需要添加更多工具
|
// 可以根据需要添加更多工具
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,72 +2,122 @@
|
|||||||
<div class="demo">
|
<div class="demo">
|
||||||
<div
|
<div
|
||||||
class="control"
|
class="control"
|
||||||
:class="{ active: item.id === activeId }"
|
:class="{ active: item.token === activeToken }"
|
||||||
v-for="(item, index) in list"
|
v-for="(item, index) in list"
|
||||||
:key="item.id"
|
:key="item.token"
|
||||||
@click="onSelect(item.id)"
|
@click="onSelect(item.token)"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<b>{{ item.name }}</b>
|
<b>{{ item.name }}</b>
|
||||||
<button
|
<button
|
||||||
v-if="index !== 0"
|
v-if="index !== 0"
|
||||||
@click="onMove(item.id, list[index - 1].id)"
|
@click="onMove(item.token, list[index - 1].token)"
|
||||||
>
|
>
|
||||||
←
|
←
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="index !== list.length - 1"
|
v-if="index !== list.length - 1"
|
||||||
@click="onMove(item.id, list[index + 1].id)"
|
@click="onMove(item.token, list[index + 1].token)"
|
||||||
>
|
>
|
||||||
→
|
→
|
||||||
</button>
|
</button>
|
||||||
<button @click.stop="onDelete(item.id)">删除</button>
|
<button @click.stop="onDelete(item.token)">删除</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>偏移X</span>
|
<span>偏移X</span>
|
||||||
<input type="number" v-model="item.location[0]" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.location[0]"
|
||||||
|
@input="updateList(item, 'location[0]', item.location[0])"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>偏移Y</span>
|
<span>偏移Y</span>
|
||||||
<input type="number" v-model="item.location[1]" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.location[1]"
|
||||||
|
@input="updateList(item, 'location[1]', item.location[1])"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>角度</span>
|
<span>角度</span>
|
||||||
<input type="number" v-model="item.angle" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.angle"
|
||||||
|
@input="updateList(item, 'angle', item.angle)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>缩放</span>
|
<span>缩放</span>
|
||||||
<input type="number" v-model="item.scale[0]" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.scale[0]"
|
||||||
|
@input="updateList(item, 'scale[0]', item.scale[0])"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>水平间距</span>
|
<span>水平间距</span>
|
||||||
<input type="number" v-model="item.object.gapX" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.object.gapX"
|
||||||
|
@input="updateList(item, 'object.gapX', item.object.gapX)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>垂直间距</span>
|
<span>垂直间距</span>
|
||||||
<input type="number" v-model="item.object.gapY" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.object.gapY"
|
||||||
|
@input="updateList(item, 'object.gapY', item.object.gapY)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<hr />
|
<hr />
|
||||||
<div>
|
<div>
|
||||||
<span>缩放X</span>
|
<span>缩放X</span>
|
||||||
<input type="number" v-model="item.object.scaleX" step="0.1" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.object.scaleX"
|
||||||
|
step="0.1"
|
||||||
|
@input="
|
||||||
|
updateList(item, 'object.scaleX', item.object.scaleX)
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>缩放Y</span>
|
<span>缩放Y</span>
|
||||||
<input type="number" v-model="item.object.scaleY" step="0.1" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.object.scaleY"
|
||||||
|
step="0.1"
|
||||||
|
@input="
|
||||||
|
updateList(item, 'object.scaleY', item.object.scaleY)
|
||||||
|
"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>X</span>
|
<span>X</span>
|
||||||
<input type="number" v-model="item.object.left" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.object.left"
|
||||||
|
@input="updateList(item, 'object.left', item.object.left)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Y</span>
|
<span>Y</span>
|
||||||
<input type="number" v-model="item.object.top" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.object.top"
|
||||||
|
@input="updateList(item, 'object.top', item.object.top)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>角度</span>
|
<span>角度</span>
|
||||||
<input type="number" v-model="item.object.angle" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="item.object.angle"
|
||||||
|
@input="updateList(item, 'object.angle', item.object.angle)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -78,6 +128,9 @@
|
|||||||
step="0.1"
|
step="0.1"
|
||||||
min="0"
|
min="0"
|
||||||
max="1"
|
max="1"
|
||||||
|
@input="
|
||||||
|
updateList(item, 'object.opacity', item.object.opacity)
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -86,6 +139,8 @@
|
|||||||
<pingpu
|
<pingpu
|
||||||
:list="list"
|
:list="list"
|
||||||
ref="pingpuRef"
|
ref="pingpuRef"
|
||||||
|
:width="600"
|
||||||
|
:height="900"
|
||||||
@change-canvas="updateCanvas"
|
@change-canvas="updateCanvas"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -105,10 +160,10 @@
|
|||||||
|
|
||||||
const convertDotNotationToBracket = (str) =>
|
const convertDotNotationToBracket = (str) =>
|
||||||
str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
|
str.replace(/(?:^|\.)(\d+)(?=\.|$)/g, "[#$1]").replace(/\[#/g, "[");
|
||||||
const activeId = ref("1");
|
const activeToken = ref("1");
|
||||||
const list = ref([
|
const list = ref([
|
||||||
{
|
{
|
||||||
id: "1",
|
token: "1",
|
||||||
ifSingle: false,
|
ifSingle: false,
|
||||||
level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
designType: "Library",
|
designType: "Library",
|
||||||
@@ -133,7 +188,7 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "2",
|
token: "2",
|
||||||
ifSingle: false,
|
ifSingle: false,
|
||||||
level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
designType: "Library",
|
designType: "Library",
|
||||||
@@ -144,12 +199,12 @@
|
|||||||
name: "Print2",
|
name: "Print2",
|
||||||
priority: 1,
|
priority: 1,
|
||||||
object: {
|
object: {
|
||||||
top: 150,
|
top: 450,
|
||||||
left: 250,
|
left: 300,
|
||||||
scaleX: 0.5,
|
scaleX: 0.5,
|
||||||
scaleY: 0.5,
|
scaleY: 0.5,
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
angle: 45,
|
angle: 0,
|
||||||
flipX: false,
|
flipX: false,
|
||||||
flipY: false,
|
flipY: false,
|
||||||
blendMode: "multiply",
|
blendMode: "multiply",
|
||||||
@@ -163,42 +218,37 @@
|
|||||||
const oldList = ref(deepCopy(list.value));
|
const oldList = ref(deepCopy(list.value));
|
||||||
const pingpuRef = ref(null);
|
const pingpuRef = ref(null);
|
||||||
const updateCanvas = (arr) => {
|
const updateCanvas = (arr) => {
|
||||||
|
console.log(arr);
|
||||||
oldList.value = deepCopy(list.value);
|
oldList.value = deepCopy(list.value);
|
||||||
arr.forEach((item) => {
|
arr.forEach((item) => {
|
||||||
list.value.forEach((v) => {
|
const obj = list.value.find((v) => v.token === item.token);
|
||||||
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
if (item.action === ACTIONS.UPDATE) {
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
if (v.id === item.id) {
|
try {
|
||||||
if (item.action === ACTIONS.UPDATE) {
|
const key = item.key;
|
||||||
try {
|
const str = /^\[/.test(item.key)
|
||||||
const key = item.key;
|
? "obj" + key
|
||||||
const str = /^\[/.test(item.key)
|
: "obj." + key;
|
||||||
? "v" + key
|
eval(`${str} = item.value`);
|
||||||
: "v." + key;
|
} catch (error) {
|
||||||
eval(`${str} = item.value`);
|
console.error(error);
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (item.action === ACTIONS.SELECT) {
|
|
||||||
activeId.value = item.id;
|
|
||||||
}
|
}
|
||||||
});
|
} else if (item.action === ACTIONS.SELECT) {
|
||||||
|
activeToken.value = item.token;
|
||||||
|
} else if (item.action === ACTIONS.DELETE) {
|
||||||
|
list.value = list.value.filter((v) => v.token !== item.token);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelect = (id) => {
|
const onSelect = (token) => {
|
||||||
activeId.value = id;
|
activeToken.value = token;
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([{ token, action: ACTIONS.SELECT }]);
|
||||||
{
|
|
||||||
id: id,
|
|
||||||
action: ACTIONS.SELECT,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
const onMove = (id, id2) => {
|
const onMove = (token1, token2) => {
|
||||||
const obj1 = list.value.find((v) => v.id === id);
|
const obj1 = list.value.find((v) => v.token === token1);
|
||||||
const obj2 = list.value.find((v) => v.id === id2);
|
const obj2 = list.value.find((v) => v.token === token2);
|
||||||
const index1 = list.value.indexOf(obj1);
|
const index1 = list.value.indexOf(obj1);
|
||||||
const index2 = list.value.indexOf(obj2);
|
const index2 = list.value.indexOf(obj2);
|
||||||
if (index1 < index2) {
|
if (index1 < index2) {
|
||||||
@@ -206,26 +256,16 @@
|
|||||||
} else {
|
} else {
|
||||||
list.value.splice(index1, 0, list.value.splice(index2, 1)[0]);
|
list.value.splice(index1, 0, list.value.splice(index2, 1)[0]);
|
||||||
}
|
}
|
||||||
const ids = list.value.map((v) => v.id);
|
const tokens = list.value.map((v) => v.token);
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([{ action: ACTIONS.SORT, tokens }]);
|
||||||
{
|
|
||||||
action: ACTIONS.SORT,
|
|
||||||
ids,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
const onDelete = (id) => {
|
const onDelete = (token) => {
|
||||||
list.value = list.value.filter((v) => v.id !== id);
|
list.value = list.value.filter((v) => v.token !== token);
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([{ token, action: ACTIONS.DELETE }]);
|
||||||
{
|
|
||||||
id: id,
|
|
||||||
action: ACTIONS.DELETE,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
const onAdd = () => {
|
const onAdd = () => {
|
||||||
const obj = {
|
const obj = {
|
||||||
id: Date.now().toString(),
|
token: Date.now().toString(),
|
||||||
ifSingle: false,
|
ifSingle: false,
|
||||||
level2Type: "Pattern",
|
level2Type: "Pattern",
|
||||||
designType: "Library",
|
designType: "Library",
|
||||||
@@ -250,59 +290,20 @@
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
list.value.push(obj);
|
list.value.push(obj);
|
||||||
|
pingpuRef.value.updataList([{ action: ACTIONS.ADD, data: obj }]);
|
||||||
|
};
|
||||||
|
// 监听列表变化属性变更
|
||||||
|
const updateList = (item, key, value) => {
|
||||||
|
if (key === "scale[0]") item.scale[1] = value;
|
||||||
pingpuRef.value.updataList([
|
pingpuRef.value.updataList([
|
||||||
{
|
{
|
||||||
action: ACTIONS.ADD,
|
token: item.token,
|
||||||
data: obj,
|
action: ACTIONS.UPDATE,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
watch(
|
|
||||||
() => list.value,
|
|
||||||
() => updateList(),
|
|
||||||
{ deep: true }
|
|
||||||
);
|
|
||||||
// 监听列表变化属性变更
|
|
||||||
const updateList = () => {
|
|
||||||
const changeList = [];
|
|
||||||
oldList.value.forEach((oldItem) => {
|
|
||||||
const newItem = list.value.find((v) => v.id === oldItem.id);
|
|
||||||
if (newItem) {
|
|
||||||
const arr = findDiffProps(oldItem, newItem);
|
|
||||||
arr.forEach((item) => {
|
|
||||||
changeList.push({
|
|
||||||
...item,
|
|
||||||
id: oldItem.id,
|
|
||||||
action: ACTIONS.UPDATE,
|
|
||||||
key: convertDotNotationToBracket(item.key),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
changeList.push({
|
|
||||||
id: oldItem.id,
|
|
||||||
action: ACTIONS.DELETE,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
oldList.value = deepCopy(list.value);
|
|
||||||
if (changeList.length) {
|
|
||||||
pingpuRef.value.updataList(changeList);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 递归查找不同的属性
|
|
||||||
const findDiffProps = (obj1, obj2, diffProps = [], path = "") => {
|
|
||||||
for (const key in obj1) {
|
|
||||||
if (typeof obj1[key] === "object") {
|
|
||||||
findDiffProps(obj1[key], obj2[key], diffProps, `${path}${key}.`);
|
|
||||||
} else if (obj1[key] !== obj2[key]) {
|
|
||||||
diffProps.push({
|
|
||||||
key: `${path}${key}`,
|
|
||||||
value: obj2[key],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return diffProps;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang='less' scoped>
|
<style lang='less' scoped>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pingpu" ref="el"><canvas ref="canvasRef"></canvas></div>
|
<div class="overall-canvas" ref="el"><canvas ref="canvasRef"></canvas></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -30,9 +30,11 @@
|
|||||||
DELETE: "delete",
|
DELETE: "delete",
|
||||||
SORT: "sort",
|
SORT: "sort",
|
||||||
};
|
};
|
||||||
const emit = defineEmits(["change-canvas"]);
|
const emit = defineEmits(["change-canvas", "init-canvas"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
list: { type: Array, default: () => [] },
|
list: { type: Array, default: () => [] },
|
||||||
|
width: { type: Number, required: true },
|
||||||
|
height: { type: Number, required: true },
|
||||||
});
|
});
|
||||||
const el = ref(null);
|
const el = ref(null);
|
||||||
const canvasRef = ref(null);
|
const canvasRef = ref(null);
|
||||||
@@ -41,7 +43,6 @@
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
initCanvas();
|
initCanvas();
|
||||||
await setCanvasData();
|
await setCanvasData();
|
||||||
|
|
||||||
let throttleTimeout = null;
|
let throttleTimeout = null;
|
||||||
let lastRunTime = 0;
|
let lastRunTime = 0;
|
||||||
let trailingTimeout = null;
|
let trailingTimeout = null;
|
||||||
@@ -63,6 +64,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
observer.value.observe(el.value);
|
observer.value.observe(el.value);
|
||||||
|
emit("init-canvas", props.list);
|
||||||
});
|
});
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
observer.value.disconnect();
|
observer.value.disconnect();
|
||||||
@@ -100,23 +102,23 @@
|
|||||||
const object = e.target;
|
const object = e.target;
|
||||||
const action = e.action;
|
const action = e.action;
|
||||||
const list = [];
|
const list = [];
|
||||||
const id = object.id;
|
const token = object.token;
|
||||||
if (action === "drag" || action === "rotate") {
|
if (action === "drag" || action === "rotate") {
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_TOP,
|
key: KEYS.O_TOP,
|
||||||
value: object.top,
|
value: (props.height / canvas.height) * object.top,
|
||||||
});
|
});
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_LEFT,
|
key: KEYS.O_LEFT,
|
||||||
value: object.left,
|
value: (props.width / canvas.width) * object.left,
|
||||||
});
|
});
|
||||||
if (action === "rotate") {
|
if (action === "rotate") {
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_ANGLE,
|
key: KEYS.O_ANGLE,
|
||||||
value: object.angle,
|
value: object.angle,
|
||||||
@@ -124,13 +126,13 @@
|
|||||||
}
|
}
|
||||||
} else if (action === "scale") {
|
} else if (action === "scale") {
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_SCALE_X,
|
key: KEYS.O_SCALE_X,
|
||||||
value: object.scaleX,
|
value: object.scaleX,
|
||||||
});
|
});
|
||||||
list.push({
|
list.push({
|
||||||
id: id,
|
token,
|
||||||
action: ACTIONS.UPDATE,
|
action: ACTIONS.UPDATE,
|
||||||
key: KEYS.O_SCALE_Y,
|
key: KEYS.O_SCALE_Y,
|
||||||
value: object.scaleY,
|
value: object.scaleY,
|
||||||
@@ -140,15 +142,17 @@
|
|||||||
};
|
};
|
||||||
// 对象选中
|
// 对象选中
|
||||||
const onObjectSelected = (e) => {
|
const onObjectSelected = (e) => {
|
||||||
const id = e.selected[0].id;
|
const token = e.selected[0].token;
|
||||||
const list = [
|
const list = [{ token, action: ACTIONS.SELECT }];
|
||||||
{
|
|
||||||
id: id,
|
|
||||||
action: ACTIONS.SELECT,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
emit("change-canvas", list);
|
emit("change-canvas", list);
|
||||||
};
|
};
|
||||||
|
// 删除对象
|
||||||
|
const onDeleteItem = (object) => {
|
||||||
|
const list = [{ token: object.token, action: ACTIONS.DELETE }];
|
||||||
|
emit("change-canvas", list);
|
||||||
|
canvas.remove(object);
|
||||||
|
canvas.renderAll();
|
||||||
|
};
|
||||||
const urlToCanvas = (url) => {
|
const urlToCanvas = (url) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fabric.Image.fromURL(
|
fabric.Image.fromURL(
|
||||||
@@ -181,17 +185,19 @@
|
|||||||
const cheight = canvas.height;
|
const cheight = canvas.height;
|
||||||
let pattern = await setFill(item);
|
let pattern = await setFill(item);
|
||||||
let rect = new fabric.Rect({
|
let rect = new fabric.Rect({
|
||||||
id: item.id,
|
token: item.token,
|
||||||
width: cwidth,
|
width: cwidth,
|
||||||
height: cheight,
|
height: cheight,
|
||||||
fill: pattern,
|
fill: pattern,
|
||||||
...item.object,
|
...item.object,
|
||||||
|
top: item.object.top / (props.height / canvas.height),
|
||||||
|
left: item.object.left / (props.width / canvas.width),
|
||||||
|
onDelete: (v) => onDeleteItem(v),
|
||||||
});
|
});
|
||||||
canvas.add(rect);
|
canvas.add(rect);
|
||||||
};
|
};
|
||||||
const setFill = async (item) => {
|
const setFill = async (item) => {
|
||||||
if (!item) return null;
|
if (!item) return null;
|
||||||
console.log(item.scale);
|
|
||||||
const cwidth = canvas.width;
|
const cwidth = canvas.width;
|
||||||
const cheight = canvas.height;
|
const cheight = canvas.height;
|
||||||
let image = await urlToCanvas(item.path);
|
let image = await urlToCanvas(item.path);
|
||||||
@@ -225,19 +231,20 @@
|
|||||||
return pattern;
|
return pattern;
|
||||||
};
|
};
|
||||||
const updataList = async (list) => {
|
const updataList = async (list) => {
|
||||||
|
console.log(list);
|
||||||
const objects = canvas.getObjects();
|
const objects = canvas.getObjects();
|
||||||
// list.forEach((item) => {
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
let item = list[i];
|
let item = list[i];
|
||||||
let object = objects.find((o) => o.id === item.id);
|
let object = objects.find((o) => o.token === item.token);
|
||||||
if (item.action === ACTIONS.UPDATE) {
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
|
if (!object) continue;
|
||||||
let value = item.value;
|
let value = item.value;
|
||||||
switch (item.key) {
|
switch (item.key) {
|
||||||
case KEYS.O_TOP:
|
case KEYS.O_TOP:
|
||||||
object.set("top", value);
|
object.set("top", value / (props.height / canvas.height));
|
||||||
break;
|
break;
|
||||||
case KEYS.O_LEFT:
|
case KEYS.O_LEFT:
|
||||||
object.set("left", value);
|
object.set("left", value / (props.width / canvas.width));
|
||||||
break;
|
break;
|
||||||
case KEYS.O_OPACITY:
|
case KEYS.O_OPACITY:
|
||||||
object.set("opacity", value);
|
object.set("opacity", value);
|
||||||
@@ -268,24 +275,23 @@
|
|||||||
case KEYS.FILL_GAPX:
|
case KEYS.FILL_GAPX:
|
||||||
case KEYS.FILL_GAPY:
|
case KEYS.FILL_GAPY:
|
||||||
let pattern = await setFill(
|
let pattern = await setFill(
|
||||||
props.list.find((v) => v.id === item.id)
|
props.list.find((v) => v.token === item.token)
|
||||||
);
|
);
|
||||||
object.set("fill", pattern);
|
object.set("fill", pattern);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (item.action === ACTIONS.SELECT) {
|
} else if (item.action === ACTIONS.SELECT) {
|
||||||
canvas.setActiveObject(object);
|
if (object) canvas.setActiveObject(object);
|
||||||
} else if (item.action === ACTIONS.SORT) {
|
} else if (item.action === ACTIONS.SORT) {
|
||||||
let ids = item.ids;
|
let tokens = item.tokens;
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
for (let j = 0; j < ids.length; j++) {
|
for (let j = 0; j < tokens.length; j++) {
|
||||||
let id = ids[j];
|
let object = objects.find((o) => o.token === tokens[j]);
|
||||||
let object = objects.find((o) => o.id === id);
|
if (object) canvas.add(object);
|
||||||
canvas.add(object);
|
|
||||||
}
|
}
|
||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
} else if (item.action === ACTIONS.DELETE) {
|
} else if (item.action === ACTIONS.DELETE) {
|
||||||
canvas.remove(object);
|
if (object) canvas.remove(object);
|
||||||
} else if (item.action === ACTIONS.ADD) {
|
} else if (item.action === ACTIONS.ADD) {
|
||||||
await addObject(item.data);
|
await addObject(item.data);
|
||||||
}
|
}
|
||||||
@@ -298,7 +304,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang='less' scoped>
|
<style lang='less' scoped>
|
||||||
.pingpu {
|
.overall-canvas {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="test" ref="testRef">
|
<!-- <div class="test" ref="testRef">
|
||||||
<!-- <div class="canvas-container">
|
<div class="canvas-container">
|
||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
</div> -->
|
</div>
|
||||||
</div>
|
</div> -->
|
||||||
|
<overall-canvas-demo />
|
||||||
|
<div style="width: 100px; height: 100px;position: relative;"><CanvasEditor /></div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { fabric } from "fabric-with-all";
|
import { fabric } from "fabric-with-all";
|
||||||
import { ref, watch, onMounted } from "vue";
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
import CanvasEditor from "./CanvasEditor/index.vue";
|
||||||
|
import OverallCanvasDemo from "./OverallCanvas/demo.vue";
|
||||||
const imageUrl = "/src/assets/images/canvas/xiangaofenge.png";
|
const imageUrl = "/src/assets/images/canvas/xiangaofenge.png";
|
||||||
const testRef = ref(null);
|
const testRef = ref(null);
|
||||||
|
|
||||||
@@ -35,53 +39,104 @@
|
|||||||
canvas1.height = height;
|
canvas1.height = height;
|
||||||
const ctx1 = canvas1.getContext("2d");
|
const ctx1 = canvas1.getContext("2d");
|
||||||
ctx1.drawImage(image, 0, 0, width, height);
|
ctx1.drawImage(image, 0, 0, width, height);
|
||||||
const data = ctx1.getImageData(0, 0, width, height);
|
const arr = traceImageContour(canvas1);
|
||||||
testRef.value.appendChild(canvas1);
|
const str = arr.map((v) => `${v.x} ${v.y}`).join(" L ");
|
||||||
const testData = test(data);
|
const path = new fabric.Path(`M ${str} z`);
|
||||||
const canvas2 = document.createElement("canvas");
|
path.set({
|
||||||
canvas2.width = width;
|
fill: "rgba(127, 255, 127, 0.3)",
|
||||||
canvas2.height = height;
|
stroke: "#2AA81B",
|
||||||
const ctx2 = canvas2.getContext("2d");
|
strokeWidth: 2,
|
||||||
ctx2.putImageData(testData, 0, 0);
|
strokeDashArray: [8, 4],
|
||||||
testRef.value.appendChild(canvas2);
|
strokeLineCap: "round",// 折线端点样式
|
||||||
|
strokeLineJoin: "bevel", // 折线连接样式
|
||||||
|
strokeUniform: true, // 保持描边宽度不随缩放改变
|
||||||
|
});
|
||||||
|
canvas.add(path);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// 获取图片轮廓点位
|
// 边界追踪
|
||||||
function test(data) {
|
function traceImageContour(canvas) {
|
||||||
// 找过的点位
|
const ctx = canvas.getContext("2d");
|
||||||
const visited = [];
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
// 轮廓点位
|
const data = imageData.data;
|
||||||
const contours = [];
|
const width = canvas.width;
|
||||||
const { width, height } = data;
|
const height = canvas.height;
|
||||||
function cd(x, y) {
|
|
||||||
const arr = [
|
// 查找起始点(第一个不透明像素)
|
||||||
[x, y], // 当前
|
let startX = -1;
|
||||||
[x, y - 1], // 上
|
let startY = -1;
|
||||||
[x + 1, y], // 右
|
|
||||||
[x, y + 1], // 下
|
outer: for (let y = 0; y < height; y++) {
|
||||||
[x - 1, y], // 左
|
for (let x = 0; x < width; x++) {
|
||||||
];
|
const index = (y * width + x) * 4;
|
||||||
for (let i = 0; i < arr.length; i++) {
|
if (data[index + 3] > 0) {
|
||||||
let [x1, y1] = arr[i];
|
startX = x;
|
||||||
if (x1 < 0 || x1 >= width || y1 < 0 || y1 >= height) continue;
|
startY = y;
|
||||||
let key = `${x1},${y1}`;
|
break outer;
|
||||||
if (visited.includes(key)) continue;
|
|
||||||
visited.push(key);
|
|
||||||
let index = (y1 * width + x1) * 4;
|
|
||||||
let r = data.data[index];
|
|
||||||
let g = data.data[index + 1];
|
|
||||||
let b = data.data[index + 2];
|
|
||||||
let a = data.data[index + 3];
|
|
||||||
if ((r || g || b) && a) {
|
|
||||||
contours.push({ x: x1, y: y1 });
|
|
||||||
} else {
|
|
||||||
if (i > 0) cd(x1, y1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cd(0, 0);
|
|
||||||
console.log(contours);
|
if (startX === -1) return []; // 没有不透明像素
|
||||||
return data;
|
|
||||||
|
// Moore-Neighbor边界跟踪算法
|
||||||
|
const contour = [];
|
||||||
|
const visited = new Set();
|
||||||
|
const directions = [
|
||||||
|
[-1, 0],
|
||||||
|
[-1, -1],
|
||||||
|
[0, -1],
|
||||||
|
[1, -1],
|
||||||
|
[1, 0],
|
||||||
|
[1, 1],
|
||||||
|
[0, 1],
|
||||||
|
[-1, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
let currentX = startX;
|
||||||
|
let currentY = startY;
|
||||||
|
let backtrackDir = 4; // 起始方向:右
|
||||||
|
|
||||||
|
do {
|
||||||
|
const pointKey = `${currentX},${currentY}`;
|
||||||
|
if (!visited.has(pointKey)) {
|
||||||
|
contour.push({ x: currentX, y: currentY });
|
||||||
|
visited.add(pointKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从右方向开始顺时针查找
|
||||||
|
let found = false;
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const dir = (backtrackDir + i) % 8;
|
||||||
|
const dx = directions[dir][0];
|
||||||
|
const dy = directions[dir][1];
|
||||||
|
const checkX = currentX + dx;
|
||||||
|
const checkY = currentY + dy;
|
||||||
|
|
||||||
|
if (
|
||||||
|
checkX >= 0 &&
|
||||||
|
checkX < width &&
|
||||||
|
checkY >= 0 &&
|
||||||
|
checkY < height
|
||||||
|
) {
|
||||||
|
const index = (checkY * width + checkX) * 4;
|
||||||
|
if (data[index + 3] > 0) {
|
||||||
|
currentX = checkX;
|
||||||
|
currentY = checkY;
|
||||||
|
backtrackDir = (dir + 5) % 8; // 下一个开始查找的方向
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) break;
|
||||||
|
} while (
|
||||||
|
!(currentX === startX && currentY === startY) &&
|
||||||
|
visited.size < width * height
|
||||||
|
);
|
||||||
|
|
||||||
|
return contour;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item detailLeft" :class="{isEditPattern:isEditPattern.value}">
|
<div class="item detailLeft" :class="{isEditPattern:isEditPattern.value}">
|
||||||
<detailLeft v-if="currentDetailType" ref="detailLeft"></detailLeft>
|
<detailLeft v-if="currentDetailType" ref="detailLeft" :detailLeftColorKey="detailLeftColorKey"></detailLeft>
|
||||||
<!-- <detailLeft v-if="selectDetail && selectDetail.id && currentDetailType"></detailLeft> -->
|
<!-- <detailLeft v-if="selectDetail && selectDetail.id && currentDetailType"></detailLeft> -->
|
||||||
<div class="btn" style="margin: 0;" v-show="currentDetailType == 'color'">
|
<div class="btn" style="margin: 0;" v-show="currentDetailType == 'color'">
|
||||||
<div class="gallery_btn" @click="previwe">{{$t('DesignPrintOperation.Preview')}}</div>
|
<div class="gallery_btn" @click="previwe">{{$t('DesignPrintOperation.Preview')}}</div>
|
||||||
@@ -61,13 +61,10 @@
|
|||||||
<model
|
<model
|
||||||
ref="model"
|
ref="model"
|
||||||
:key="positionKey"
|
:key="positionKey"
|
||||||
@addDetail="addDetail"
|
|
||||||
@canvasReload="canvasReload"
|
|
||||||
@detailEdit="detailEdit"
|
@detailEdit="detailEdit"
|
||||||
@addSketch="()=>isEditPattern.value = ''"
|
@addSketch="()=>isEditPattern.value = ''"
|
||||||
@revocation="revocation"
|
@revocation="revocation"
|
||||||
@oppositeRevocation="oppositeRevocation"
|
@oppositeRevocation="oppositeRevocation"
|
||||||
@modelOnLoad="modelOnLoad"
|
|
||||||
@sketchSysToLibrary="sketchSysToLibrary"
|
@sketchSysToLibrary="sketchSysToLibrary"
|
||||||
></model>
|
></model>
|
||||||
<div class="btn">
|
<div class="btn">
|
||||||
@@ -88,7 +85,7 @@
|
|||||||
" alt="">
|
" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="contentRight" v-else-if="currentDetailType && !isEditPattern.value">
|
<div class="contentRight" v-else-if="currentDetailType && !isEditPattern.value">
|
||||||
<detailRight ref="detailRight"></detailRight>
|
<detailRight ref="detailRight" :sketchSize="sketchSize"></detailRight>
|
||||||
<div class="btn"
|
<div class="btn"
|
||||||
v-show="
|
v-show="
|
||||||
currentDetailType !== 'color' &&
|
currentDetailType !== 'color' &&
|
||||||
@@ -103,15 +100,14 @@
|
|||||||
<div class="gallery_btn" @click="previwe">{{$t('DesignPrintOperation.Preview')}}</div>
|
<div class="gallery_btn" @click="previwe">{{$t('DesignPrintOperation.Preview')}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="contentRight" v-if="selectDetail && selectDetail.id && currentDetailType && isEditPattern.value">
|
<div class="contentRight canvas" v-if="selectDetail && selectDetail.id && currentDetailType" :class="{'active': isEditPattern.value}">
|
||||||
<canvasBox ref="canvasBox" :key="canvasKey || isEditPattern.value" :isEditPattern="isEditPattern.value"></canvasBox>
|
<canvasBox ref="canvasBox" :key="canvasKey" :sketchSize="sketchSize" @setSloganData="setSloganData" :isEditPattern="isEditPattern.value" :updateOtherLayers="updateOtherLayers"></canvasBox>
|
||||||
</div>
|
</div>
|
||||||
<!-- 画布 -->
|
<!-- 画布 -->
|
||||||
<!-- <div class="content" v-else-if="selectDetail && selectDetail.id">
|
<!-- <div class="content" v-else-if="selectDetail && selectDetail.id">
|
||||||
</div> -->
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<addDetails ref="addDetails" @setSloganData="setSloganData"></addDetails>
|
|
||||||
</a-modal>
|
</a-modal>
|
||||||
<div class="mark_loading" v-show="loadingShow">
|
<div class="mark_loading" v-show="loadingShow">
|
||||||
<a-spin size="large" />
|
<a-spin size="large" />
|
||||||
@@ -130,14 +126,13 @@ import canvasBox from './canvas/index.vue'
|
|||||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||||
import { Https } from "@/tool/https";
|
import { Https } from "@/tool/https";
|
||||||
import { Modal,message } from 'ant-design-vue';
|
import { Modal,message } from 'ant-design-vue';
|
||||||
import {getUploadUrl,isMoible,setGradual} from '@/tool/util'
|
import {getUploadUrl,segmentImage,setGradual,rgbToHsv,rgbaToHex} from '@/tool/util'
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import { openGuide,driverObj__ } from "@/tool/guide";
|
import { openGuide,driverObj__ } from "@/tool/guide";
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import addDetails from '@/component/Detail/addDetails.vue'
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components:{
|
||||||
detailLeft,model,detailRight,canvasBox,addDetails
|
detailLeft,model,detailRight,canvasBox
|
||||||
},
|
},
|
||||||
emits:['destroy'],
|
emits:['destroy'],
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
@@ -148,7 +143,6 @@ export default defineComponent({
|
|||||||
canvasBox,
|
canvasBox,
|
||||||
detailRight,
|
detailRight,
|
||||||
detailLeft:null as any,
|
detailLeft:null as any,
|
||||||
addDetails:null as any,
|
|
||||||
})
|
})
|
||||||
const userDetail = computed(()=>{
|
const userDetail = computed(()=>{
|
||||||
return store.state.UserHabit.userDetail
|
return store.state.UserHabit.userDetail
|
||||||
@@ -157,10 +151,12 @@ export default defineComponent({
|
|||||||
selectObject:computed(()=>store.state.Workspace.probjects) as any,//选择的项目
|
selectObject:computed(()=>store.state.Workspace.probjects) as any,//选择的项目
|
||||||
designDetail:computed(()=>store.state.DesignDetail.designDetail),
|
designDetail:computed(()=>store.state.DesignDetail.designDetail),
|
||||||
currentDetailType:computed(()=>store.state.DesignDetail.currentDetailType),
|
currentDetailType:computed(()=>store.state.DesignDetail.currentDetailType),
|
||||||
|
frontBack:computed(()=>store.state.DesignDetail.frontBack),
|
||||||
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
|
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
|
||||||
designDetailShow:false,
|
designDetailShow:false,
|
||||||
loadingShow:false,
|
loadingShow:false,
|
||||||
oppositeRevocationShow:-1,
|
oppositeRevocationShow:-1,
|
||||||
|
imgDomIndex:-1,
|
||||||
revocationShow:-1,
|
revocationShow:-1,
|
||||||
isEditPattern:{
|
isEditPattern:{
|
||||||
value:'' as any,
|
value:'' as any,
|
||||||
@@ -173,10 +169,30 @@ export default defineComponent({
|
|||||||
fun:null,
|
fun:null,
|
||||||
},
|
},
|
||||||
positionKey:0,
|
positionKey:0,
|
||||||
isUndividedLayerWithSinglePrint:false,
|
detailLeftColorKey:0,
|
||||||
|
sketchSize:{
|
||||||
|
width:0,
|
||||||
|
height:0,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
const getSketchSize:any = async ()=>{
|
||||||
|
let img = new Image();
|
||||||
|
img.src = detailData.selectDetail.path;
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
img.onload = () => {
|
||||||
|
detailData.sketchSize.width = img.width
|
||||||
|
detailData.sketchSize.height = img.height
|
||||||
|
resolve([img.width, img.height]);
|
||||||
|
}
|
||||||
|
img.onerror = reject;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
watch(()=>detailData.selectDetail,async (newValue,oldValue)=>{
|
||||||
|
detailData.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
|
||||||
|
if(newValue)await getSketchSize()
|
||||||
|
detailData.canvasKey += 1
|
||||||
|
// privewDetail(oldValue)
|
||||||
|
},{immediate: true})
|
||||||
provide('getCanvasIfEdit',detailData.getCanvasIfEdit)
|
provide('getCanvasIfEdit',detailData.getCanvasIfEdit)
|
||||||
provide('singleOveral',detailData.singleOveral)
|
provide('singleOveral',detailData.singleOveral)
|
||||||
provide('isEditPattern',detailData.isEditPattern)
|
provide('isEditPattern',detailData.isEditPattern)
|
||||||
@@ -195,6 +211,11 @@ export default defineComponent({
|
|||||||
detailData.loadingShow = true
|
detailData.loadingShow = true
|
||||||
Https.axiosGet(url).then(
|
Https.axiosGet(url).then(
|
||||||
async (rv: any) => {
|
async (rv: any) => {
|
||||||
|
//清除画布JSON数据
|
||||||
|
sessionStorage.removeItem('canvasList');
|
||||||
|
sessionStorage.removeItem('revocation');
|
||||||
|
sessionStorage.removeItem('oppositeRevocation');
|
||||||
|
sessionStorage.setItem('key', 'value');
|
||||||
store.commit('DesignDetail/setDesignDetail',rv)
|
store.commit('DesignDetail/setDesignDetail',rv)
|
||||||
rv.clothes.forEach((item:any)=>{
|
rv.clothes.forEach((item:any)=>{
|
||||||
let a
|
let a
|
||||||
@@ -228,25 +249,17 @@ export default defineComponent({
|
|||||||
element.designType = 'Library'
|
element.designType = 'Library'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(!item.layersObject[0].undividedLayerWithSinglePrint){
|
|
||||||
detailData.isUndividedLayerWithSinglePrint = true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
detailData.singleOveral.value = rv.singleOverall
|
detailData.singleOveral.value = rv.singleOverall
|
||||||
detailData.designDetailShow = true
|
detailData.designDetailShow = true
|
||||||
// this.deleteShow = false
|
// this.deleteShow = false
|
||||||
initialize()
|
|
||||||
setRevocation()
|
setRevocation()
|
||||||
if(rv.singleOverall == "single"){
|
if(rv.singleOverall == "single"){
|
||||||
store.commit('DesignDetail/setDesignColthes',rv.clothes[0].id)
|
store.commit('DesignDetail/setDesignColthes',rv.clothes[0].id)
|
||||||
modelOnLoad()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(detailData.isUndividedLayerWithSinglePrint){
|
detailData.loadingShow = false
|
||||||
}else{
|
|
||||||
detailData.loadingShow = false
|
|
||||||
}
|
|
||||||
resolve(rv)
|
resolve(rv)
|
||||||
}
|
}
|
||||||
).catch(rv=>{
|
).catch(rv=>{
|
||||||
@@ -256,12 +269,6 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
const initialize = ()=>{//design后初始化
|
|
||||||
|
|
||||||
|
|
||||||
sessionStorage.removeItem('oppositeRevocation')
|
|
||||||
sessionStorage.removeItem('revocation')
|
|
||||||
}
|
|
||||||
//撤回
|
//撤回
|
||||||
const setRevocation = ()=>{//设置撤销
|
const setRevocation = ()=>{//设置撤销
|
||||||
let itemDetail = JSON.parse(JSON.stringify(detailData.designDetail))
|
let itemDetail = JSON.parse(JSON.stringify(detailData.designDetail))
|
||||||
@@ -320,13 +327,15 @@ export default defineComponent({
|
|||||||
const setCurrentDetail = (str:string)=>{
|
const setCurrentDetail = (str:string)=>{
|
||||||
store.commit('DesignDetail/setCurrentDetailType',str)
|
store.commit('DesignDetail/setCurrentDetailType',str)
|
||||||
}
|
}
|
||||||
const setClothes = async (list:any)=>{
|
const setClothes = async (list:any,str:string)=>{
|
||||||
let clothesList:any = []
|
let clothesList:any = []
|
||||||
await nextTick()
|
await nextTick()
|
||||||
|
if(detailData.isEditPattern.value == 'editSketch')await detailDom.canvasBox.submitBase64Data().then((rv)=>{
|
||||||
|
detailData.selectDetail.sketchString = rv
|
||||||
|
})
|
||||||
for(let i = 0;i<list.length;i++){
|
for(let i = 0;i<list.length;i++){
|
||||||
detailData.selectDetail
|
detailData.selectDetail
|
||||||
let {scale,offset,priority,maskUrl,maskMinioUrl} = await (detailDom.model as any).getSubmitData(list[i],detailData.isUndividedLayerWithSinglePrint)
|
let {scale,offset,priority,transpose,rotate,maskUrl,maskMinioUrl} = await (detailDom.model as any).getSubmitData(list[i])
|
||||||
if(detailDom.canvasBox?.privewDetail)await (detailDom.canvasBox as any).privewDetail()
|
|
||||||
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
||||||
let gradient = null
|
let gradient = null
|
||||||
let newData = list[i]?.newDetail?.[detailData.currentDetailType]
|
let newData = list[i]?.newDetail?.[detailData.currentDetailType]
|
||||||
@@ -349,6 +358,32 @@ export default defineComponent({
|
|||||||
detailData.selectDetail.maskUrl = ''
|
detailData.selectDetail.maskUrl = ''
|
||||||
detailData.selectDetail.maskMinioUrl = ''
|
detailData.selectDetail.maskMinioUrl = ''
|
||||||
}
|
}
|
||||||
|
function isNetworkPath(str) {
|
||||||
|
if (typeof str !== 'string' || str.trim() === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const urlPatterns = [
|
||||||
|
/^https?:\/\//i, // http:// 或 https://
|
||||||
|
/^ftp:\/\//i, // ftp://
|
||||||
|
/^ws:\/\//i, // ws://
|
||||||
|
/^wss:\/\//i, // wss://
|
||||||
|
/^\/\//, // 协议相对路径 //example.com
|
||||||
|
/^data:/i, // data:image/png;base64,...(这是Base64,不是网络路径)
|
||||||
|
];
|
||||||
|
// 排除data:URL(这实际上是Base64)
|
||||||
|
if (str.startsWith('data:')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlPatterns.some(pattern => pattern.test(str));
|
||||||
|
}
|
||||||
|
const printObjectToJSON = (list:any)=>{
|
||||||
|
if(list?.length > 0){
|
||||||
|
list.forEach((item:any)=>{
|
||||||
|
if(item.object)item.object = JSON.stringify(item.object)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
let data:any = {
|
let data:any = {
|
||||||
changed:false,
|
changed:false,
|
||||||
color,
|
color,
|
||||||
@@ -356,13 +391,15 @@ export default defineComponent({
|
|||||||
id:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.id:list[i].id,
|
id:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.id:list[i].id,
|
||||||
maskMinioUrl:((newData && detailData.currentDetailType == 'sketch') || list[i].sketchString)?'':list[i]?.maskMinioUrl,
|
maskMinioUrl:((newData && detailData.currentDetailType == 'sketch') || list[i].sketchString)?'':list[i]?.maskMinioUrl,
|
||||||
// maskUrl:'',
|
// maskUrl:'',
|
||||||
maskUrl:((newData && detailData.currentDetailType == 'sketch') || list[i].sketchString)?'':list[i]?.maskUrl,
|
maskUrl:list[i]?.maskUrl || '',
|
||||||
// offset:[
|
// offset:[
|
||||||
// -233.13985,
|
// -233.13985,
|
||||||
// 406.90964
|
// 406.90964
|
||||||
// ],
|
// ],
|
||||||
offset,
|
offset,
|
||||||
partialDesign:list[i].partialDesign || {},
|
transpose,
|
||||||
|
rotate,
|
||||||
|
partialDesign:list[i].partialDesign,
|
||||||
// partialDesign:detailData.isEditPattern.value?list[i].partialDesign:{},
|
// partialDesign:detailData.isEditPattern.value?list[i].partialDesign:{},
|
||||||
path:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.minIOPath:list[i].minIOPath,
|
path:(newData && detailData.currentDetailType == 'sketch' && isCurrent && !detailData.isEditPattern.value)?newData.minIOPath:list[i].minIOPath,
|
||||||
printObject:(newData && detailData.currentDetailType == 'print' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].printObject?list[i].printObject:{prints:[]},
|
printObject:(newData && detailData.currentDetailType == 'print' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].printObject?list[i].printObject:{prints:[]},
|
||||||
@@ -377,6 +414,8 @@ export default defineComponent({
|
|||||||
trims:(newData && detailData.currentDetailType == 'element' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].trims?.prints?list[i].trims:{prints:[]},
|
trims:(newData && detailData.currentDetailType == 'element' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].trims?.prints?list[i].trims:{prints:[]},
|
||||||
accessory:(newData && detailData.currentDetailType == 'accessory' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].trims?.prints?list[i].trims:{prints:[]},
|
accessory:(newData && detailData.currentDetailType == 'accessory' && isCurrent && !detailData.isEditPattern.value)?{prints:newData}:list[i].trims?.prints?list[i].trims:{prints:[]},
|
||||||
}
|
}
|
||||||
|
data.printObject.prints = printObjectToJSON(data.printObject.prints)
|
||||||
|
data.trims.prints = printObjectToJSON(data.trims.prints)
|
||||||
if((detailData.isEditPattern.value && list[i].color?.gradient) || (!detailData.isEditPattern.value && (list[i].newDetail?.color?.gradient || list[i].color?.gradient))){
|
if((detailData.isEditPattern.value && list[i].color?.gradient) || (!detailData.isEditPattern.value && (list[i].newDetail?.color?.gradient || list[i].color?.gradient))){
|
||||||
gradient = list[i].newDetail?.color?.gradient || list[i].color.gradient
|
gradient = list[i].newDetail?.color?.gradient || list[i].color.gradient
|
||||||
gradient.colorImg = await setGradual(gradient,320,700)
|
gradient.colorImg = await setGradual(gradient,320,700)
|
||||||
@@ -391,10 +430,10 @@ export default defineComponent({
|
|||||||
let workspace = store.state.Workspace.probjects
|
let workspace = store.state.Workspace.probjects
|
||||||
if(!detailData?.selectDetail?.path && !detailData?.selectDetail?.newDetail?.sketch?.minIOPath)return
|
if(!detailData?.selectDetail?.path && !detailData?.selectDetail?.newDetail?.sketch?.minIOPath)return
|
||||||
let clothes:any
|
let clothes:any
|
||||||
if(detailData.currentDetailType == 'models' || detailData.isUndividedLayerWithSinglePrint){
|
if(detailData.currentDetailType == 'models'){
|
||||||
clothes = await setClothes(detailData.designDetail.clothes)
|
clothes = await setClothes(detailData.designDetail.clothes,str)
|
||||||
}else{
|
}else{
|
||||||
clothes = await setClothes([detailData.selectDetail])
|
clothes = await setClothes([detailData.selectDetail],str)
|
||||||
}
|
}
|
||||||
let data = {
|
let data = {
|
||||||
designItemId:detailData.designDetail.designItemId,
|
designItemId:detailData.designDetail.designItemId,
|
||||||
@@ -405,6 +444,7 @@ export default defineComponent({
|
|||||||
sketchString:'',
|
sketchString:'',
|
||||||
modelId:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.id:detailData.designDetail.oldModel?detailData.designDetail.oldModel.id:'',
|
modelId:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.id:detailData.designDetail.oldModel?detailData.designDetail.oldModel.id:'',
|
||||||
modelType:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.type:detailData.designDetail.oldModel?detailData.designDetail.oldModel.type:'',
|
modelType:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.type:detailData.designDetail.oldModel?detailData.designDetail.oldModel.type:'',
|
||||||
|
designType:detailData.selectDetail.id?'merage':'default',
|
||||||
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
|
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||||
processId:userDetail.value.userId,
|
processId:userDetail.value.userId,
|
||||||
probjectId:store.state.Workspace.probjects.id,
|
probjectId:store.state.Workspace.probjects.id,
|
||||||
@@ -417,10 +457,10 @@ export default defineComponent({
|
|||||||
fun:setRevocation
|
fun:setRevocation
|
||||||
}
|
}
|
||||||
if(detailData?.designDetail?.newModel)detailData.designDetail.oldModel = JSON.parse(JSON.stringify(detailData.designDetail.newModel))
|
if(detailData?.designDetail?.newModel)detailData.designDetail.oldModel = JSON.parse(JSON.stringify(detailData.designDetail.newModel))
|
||||||
delete detailData.designDetail.newModel
|
// delete detailData.designDetail.newModel
|
||||||
|
detailData.selectDetail.sketchString = null
|
||||||
store.commit('DesignDetail/setPraeview',value)
|
store.commit('DesignDetail/setPraeview',value)
|
||||||
detailData.loadingShow = false
|
detailData.loadingShow = false
|
||||||
detailData.isUndividedLayerWithSinglePrint = false
|
|
||||||
canvasReload()
|
canvasReload()
|
||||||
// setRevocation()
|
// setRevocation()
|
||||||
}).catch(res=>{
|
}).catch(res=>{
|
||||||
@@ -429,7 +469,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
const submit = async ()=>{
|
const submit = async ()=>{
|
||||||
let workspace = store.state.Workspace.probjects
|
let workspace = store.state.Workspace.probjects
|
||||||
let clothes:any = await setClothes(detailData.designDetail.clothes)
|
let clothes:any = await setClothes(detailData.designDetail.clothes,'sub')
|
||||||
let data = {
|
let data = {
|
||||||
designItemId:detailData.designDetail.designItemId,
|
designItemId:detailData.designDetail.designItemId,
|
||||||
designSingleItemDTOList:clothes,
|
designSingleItemDTOList:clothes,
|
||||||
@@ -439,13 +479,21 @@ export default defineComponent({
|
|||||||
sketchString:'',
|
sketchString:'',
|
||||||
modelId:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.id:detailData.designDetail.oldModel?detailData.designDetail.oldModel.id:'',
|
modelId:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.id:detailData.designDetail.oldModel?detailData.designDetail.oldModel.id:'',
|
||||||
modelType:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.type:detailData.designDetail.oldModel?detailData.designDetail.oldModel.type:'',
|
modelType:(detailData.currentDetailType == 'models' && detailData.designDetail.newModel)?detailData.designDetail.newModel.type:detailData.designDetail.oldModel?detailData.designDetail.oldModel.type:'',
|
||||||
|
designType:detailData.selectDetail.id?'merage':'default',
|
||||||
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
|
timeZone:Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||||
processId:userDetail.value.userId,
|
processId:userDetail.value.userId,
|
||||||
probjectId:store.state.Workspace.probjects.id,
|
probjectId:store.state.Workspace.probjects.id,
|
||||||
}
|
}
|
||||||
detailData.loadingShow = true
|
detailData.loadingShow = true
|
||||||
Https.axiosPost(Https.httpUrls.designSingle, data).then((rv)=>{
|
Https.axiosPost(Https.httpUrls.designSingle, data).then(async (rv)=>{
|
||||||
|
saveCanvasJSONToSession()
|
||||||
// store.commit('DesignDetail/setPraeview',rv)
|
// store.commit('DesignDetail/setPraeview',rv)
|
||||||
|
const sessionCanvasList = sessionStorage.getItem('canvasList');
|
||||||
|
const canvasList = sessionCanvasList ? JSON.parse(sessionCanvasList) : []
|
||||||
|
for (let i = 0; i < canvasList.length; i++) {
|
||||||
|
const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasList[i].id);
|
||||||
|
if(index>-1)await detailDom.canvasBox.saveCanvas(canvasList[i])
|
||||||
|
}
|
||||||
let designCollectionList = store.state.HomeStoreModule.designCollectionList
|
let designCollectionList = store.state.HomeStoreModule.designCollectionList
|
||||||
let likeDesignCollectionList = store.state.HomeStoreModule.likeDesignCollectionList
|
let likeDesignCollectionList = store.state.HomeStoreModule.likeDesignCollectionList
|
||||||
designCollectionList.forEach((item:any) => {
|
designCollectionList.forEach((item:any) => {
|
||||||
@@ -466,45 +514,191 @@ export default defineComponent({
|
|||||||
detailData.loadingShow = false
|
detailData.loadingShow = false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const previwe = ()=>{
|
const previwe = async ()=>{
|
||||||
let data = getSubmitData('preview')
|
if((detailData.currentDetailType == 'sketch' && !detailData.isEditPattern.value) || detailData.isEditPattern.value == 'editSketch'){
|
||||||
store.dispatch('DesignDetail/setSubmit',data)
|
let data = getSubmitData('preview')
|
||||||
}
|
|
||||||
const modelOnLoad = ()=>{
|
|
||||||
if(!detailData.isUndividedLayerWithSinglePrint)return
|
|
||||||
setTimeout(()=>{
|
|
||||||
let data = getSubmitData('sub')
|
|
||||||
store.dispatch('DesignDetail/setSubmit',data)
|
store.dispatch('DesignDetail/setSubmit',data)
|
||||||
|
}else{
|
||||||
|
//走画布合成图片并且直接分割
|
||||||
|
if(detailData.isEditPattern.value !== 'canvasEditor'){
|
||||||
|
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
||||||
|
let otherData = await updateOtherLayers('single')
|
||||||
|
await detailDom.canvasBox.updateOtherLayers(otherData)
|
||||||
|
}
|
||||||
|
await detailDom.canvasBox.privewDetail()
|
||||||
|
let img = new Image()
|
||||||
|
img.onload = ()=>{
|
||||||
|
let partialDesign = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath
|
||||||
|
let size = {
|
||||||
|
width:img.width,
|
||||||
|
height:img.height,
|
||||||
|
}
|
||||||
|
segmentImage(detailData.selectDetail.maskUrl,partialDesign,size).then(async (rv)=>{
|
||||||
|
let front = detailData.frontBack.front[detailData.imgDomIndex]
|
||||||
|
let back = detailData.frontBack.back[detailData.imgDomIndex]
|
||||||
|
if(!front?.oldImageUrl)front.oldImageUrl = front.imageUrl
|
||||||
|
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
|
||||||
|
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
|
||||||
|
if(!front?.oldMaskUrl)store.commit('DesignDetail/updataDetailItem',{maskUrl:front.oldMaskUrl})
|
||||||
|
|
||||||
|
front.imageUrl = rv.targetFrontUrl
|
||||||
|
back.imageUrl = rv.targetBackUrl
|
||||||
|
store.commit('DesignDetail/canvasPreviewUpdata',{type:detailData.isEditPattern.value?'all':detailData.currentDetailType,callBack:setRevocation})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
img.src = detailData.selectDetail.path
|
||||||
|
saveCanvasJSONToSession()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const saveCanvasJSONToSession = ()=>{
|
||||||
|
let canvasJSON = detailDom.canvasBox.getCanvasJSON()
|
||||||
|
const sessionCanvasList = sessionStorage.getItem('canvasList');
|
||||||
|
const list = sessionCanvasList ? JSON.parse(sessionCanvasList) : []
|
||||||
|
let index = -1
|
||||||
|
list.forEach((item:any,i:number)=>{
|
||||||
|
if(item.id == detailData.selectDetail.id){
|
||||||
|
index = i
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
if(index < 0){
|
||||||
|
list.push({id:detailData.selectDetail.id,canvasJSON:canvasJSON})
|
||||||
|
}else{
|
||||||
|
list[index].canvasJSON = canvasJSON
|
||||||
|
}
|
||||||
|
sessionStorage.setItem('canvasList', JSON.stringify(list));
|
||||||
}
|
}
|
||||||
const detailEdit = async (str:any)=>{
|
const detailEdit = async (str:any)=>{
|
||||||
if(str){
|
if(str){
|
||||||
if(detailData.isEditPattern.value && detailData.isEditPattern.value == str){
|
if(detailData.isEditPattern.value && detailData.isEditPattern.value == str){
|
||||||
await detailDom.canvasBox.saveCanvas()
|
// await detailDom.canvasBox.saveCanvas()
|
||||||
|
await (detailDom.canvasBox as any).privewDetail()
|
||||||
|
if(detailData.isEditPattern.value == 'canvasEditor')await uploadElement()
|
||||||
detailData.isEditPattern.value = ''
|
detailData.isEditPattern.value = ''
|
||||||
}else{
|
}else{
|
||||||
if(detailData.isEditPattern.value){
|
// if(detailData.isEditPattern.value && (str == 'canvasEditor' || str == 'redGreenExample')){
|
||||||
detailDom.canvasBox.editFront(str)
|
// detailDom.canvasBox.editFront(str)
|
||||||
}
|
// }
|
||||||
|
detailDom.canvasBox.editFront(str)
|
||||||
|
let otherData = await updateOtherLayers('single')
|
||||||
|
await detailDom.canvasBox.updateOtherLayers(otherData)
|
||||||
detailData.isEditPattern.value = str
|
detailData.isEditPattern.value = str
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
detailData.isEditPattern.value = ''
|
detailData.isEditPattern.value = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const getColorName = (color:any)=>{
|
||||||
|
let rgb:any = [color.r, color.g, color.b];
|
||||||
|
let hsv = rgbToHsv(rgb);
|
||||||
|
let data = [{
|
||||||
|
h: hsv[0],
|
||||||
|
s: hsv[1],
|
||||||
|
v: hsv[2],
|
||||||
|
}]
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Https.axiosPost(Https.httpUrls.getRgbByHsvBatch, data)
|
||||||
|
.then((rv) => {
|
||||||
|
if (rv) {
|
||||||
|
resolve(rv[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((res) => {
|
||||||
|
resolve({name:'--',tcx:'--'})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const updateOtherLayers = async (str:any='all')=>{//更新到画布图层
|
||||||
|
let otherData:any = {}
|
||||||
|
if(detailDom.detailRight?.privewDetail)await (detailDom.detailRight as any).privewDetail()
|
||||||
|
if(str == 'all'){
|
||||||
|
otherData = {
|
||||||
|
color: detailData.selectDetail.newDetail?.color.r?detailData.selectDetail.newDetail?.color:detailData.selectDetail.color,
|
||||||
|
printObject: detailData.selectDetail.newDetail?.print?.length>0?{prints:detailData.selectDetail.newDetail?.print}:detailData.selectDetail.printObject || null,
|
||||||
|
trims: detailData.selectDetail.newDetail?.element?.length>0?detailData.selectDetail.newDetail?.element:detailData.selectDetail.trims || null,
|
||||||
|
}
|
||||||
|
}else if(str == 'single'){
|
||||||
|
otherData = {
|
||||||
|
color: detailData.selectDetail.color,
|
||||||
|
printObject: detailData.selectDetail.printObject || null,
|
||||||
|
trims: detailData.selectDetail.trims || null,
|
||||||
|
}
|
||||||
|
if(detailData.currentDetailType == 'color'){
|
||||||
|
let color = detailData.selectDetail.newDetail?.color
|
||||||
|
// let colorData:any = await getColorName(color?.rgba)
|
||||||
|
if(detailData.selectDetail.newDetail?.color){
|
||||||
|
if(color.r){
|
||||||
|
color.rgba = {r:color.r,g:color.g,b:color.b,a:color.a}
|
||||||
|
}else{
|
||||||
|
color.rbga = {}
|
||||||
|
}
|
||||||
|
otherData.color = color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(detailData.currentDetailType == 'print'){
|
||||||
|
otherData.printObject = {prints:detailData.selectDetail.newDetail?.print}
|
||||||
|
}
|
||||||
|
if(detailData.currentDetailType == 'element'){
|
||||||
|
otherData.trims = detailData.selectDetail.newDetail?.element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(JSON.parse(JSON.stringify(otherData)),'=======',JSON.parse(JSON.stringify(detailData.selectDetail)))
|
||||||
|
return otherData
|
||||||
|
}
|
||||||
|
const uploadElement = async ()=>{//取出画布数据更新到detail
|
||||||
|
if(detailData.isEditPattern.value == 'canvasEditor'){
|
||||||
|
// await detailDom.canvasBox.saveCanvas()
|
||||||
|
const allInfo = await (detailDom.canvasBox as any).getCanvasElement()
|
||||||
|
console.log(allInfo,'allInfo')
|
||||||
|
if(allInfo.trims?.length > 0){
|
||||||
|
// detailData.selectDetail.trims.prints = allInfo.trims
|
||||||
|
let value = {
|
||||||
|
data:allInfo.trims,
|
||||||
|
str:'element'
|
||||||
|
}
|
||||||
|
store.commit('DesignDetail/setNewDetail',value)
|
||||||
|
}
|
||||||
|
if(allInfo.prints?.length > 0){
|
||||||
|
// detailData.selectDetail.printObject.prints = allInfo.prints
|
||||||
|
let value = {
|
||||||
|
data:allInfo.prints,
|
||||||
|
str:'print'
|
||||||
|
}
|
||||||
|
store.commit('DesignDetail/setNewDetail',value)
|
||||||
|
}
|
||||||
|
if(allInfo.color?.color?.rgba){
|
||||||
|
let canvasColor = allInfo.color.color
|
||||||
|
let colorData:any = await getColorName(allInfo.color.color?.rgba)
|
||||||
|
let value:any = {
|
||||||
|
data:{
|
||||||
|
hsv:{
|
||||||
|
h:colorData.h,
|
||||||
|
s:colorData.s,
|
||||||
|
v:colorData.v,
|
||||||
|
},
|
||||||
|
name:colorData.name,
|
||||||
|
tcx:colorData.tcx,
|
||||||
|
rgba:canvasColor.rgba,
|
||||||
|
hex:rgbaToHex([canvasColor.rgba.r,canvasColor.rgba.g,canvasColor.rgba.b]),
|
||||||
|
},
|
||||||
|
str:'color'
|
||||||
|
}
|
||||||
|
if(canvasColor.gradient){
|
||||||
|
value.data.gradient = canvasColor.gradient
|
||||||
|
}
|
||||||
|
store.commit('DesignDetail/setNewDetail',value)
|
||||||
|
if(allInfo.color.color.gradient)detailData.selectDetail.color.gradient = allInfo.color.color.gradient
|
||||||
|
if(detailData.currentDetailType == 'color'){
|
||||||
|
detailData.detailLeftColorKey++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
const canvasReload = async ()=>{
|
const canvasReload = async ()=>{
|
||||||
if(detailData.isEditPattern.value){
|
if(detailData.isEditPattern.value){
|
||||||
await detailDom.canvasBox.saveCanvas()
|
await detailDom.canvasBox.saveCanvas()
|
||||||
}
|
}
|
||||||
detailData.canvasKey += 1
|
detailData.canvasKey += 1
|
||||||
}
|
}
|
||||||
let time = null as any
|
|
||||||
const handleResize = ()=>{
|
|
||||||
clearTimeout(time)
|
|
||||||
time = setTimeout(()=>{
|
|
||||||
store.commit('DesignDetail/setDesignDetail',detailData.designDetail)
|
|
||||||
},1000)
|
|
||||||
}
|
|
||||||
const sketchSysToLibrary = ()=>{//系统sketch添加到library更新library
|
const sketchSysToLibrary = ()=>{//系统sketch添加到library更新library
|
||||||
coverRevocation()
|
coverRevocation()
|
||||||
detailDom.detailLeft.sketchSysToLibrary()
|
detailDom.detailLeft.sketchSysToLibrary()
|
||||||
@@ -516,11 +710,6 @@ export default defineComponent({
|
|||||||
sessionStorage.setItem('revocation', JSON.stringify(revocation));
|
sessionStorage.setItem('revocation', JSON.stringify(revocation));
|
||||||
sessionStorage.setItem('oppositeRevocation',JSON.stringify([]));
|
sessionStorage.setItem('oppositeRevocation',JSON.stringify([]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const addDetail = () =>{
|
|
||||||
let addDetails:any = detailDom.addDetails
|
|
||||||
addDetails.init(detailData.selectDetail,'')
|
|
||||||
}
|
|
||||||
const setSloganData = (data:any)=>{
|
const setSloganData = (data:any)=>{
|
||||||
detailData.selectDetail.sketchString = data
|
detailData.selectDetail.sketchString = data
|
||||||
if(detailData.currentDetailType == 'sketch' && detailData.selectDetail?.newDetail?.sketch){
|
if(detailData.currentDetailType == 'sketch' && detailData.selectDetail?.newDetail?.sketch){
|
||||||
@@ -528,14 +717,12 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
window.addEventListener('resize', handleResize);
|
|
||||||
})
|
})
|
||||||
onBeforeUnmount(()=>{
|
onBeforeUnmount(()=>{
|
||||||
sessionStorage.removeItem('oppositeRevocation')
|
sessionStorage.removeItem('oppositeRevocation')
|
||||||
sessionStorage.removeItem('revocation')
|
sessionStorage.removeItem('revocation')
|
||||||
store.commit('DesignDetail/clearDesignDetail')
|
store.commit('DesignDetail/clearDesignDetail')
|
||||||
|
|
||||||
window.removeEventListener('resize', handleResize);
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return{
|
return{
|
||||||
@@ -551,10 +738,9 @@ export default defineComponent({
|
|||||||
oppositeRevocation,
|
oppositeRevocation,
|
||||||
detailEdit,
|
detailEdit,
|
||||||
canvasReload,
|
canvasReload,
|
||||||
modelOnLoad,
|
|
||||||
sketchSysToLibrary,
|
sketchSysToLibrary,
|
||||||
addDetail,
|
|
||||||
setSloganData,
|
setSloganData,
|
||||||
|
updateOtherLayers,//更新到画布图层 再canvasInit中执行
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -680,6 +866,24 @@ export default defineComponent({
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
&.canvas{
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
flex: auto;
|
||||||
|
width: 35vw;
|
||||||
|
height: 80vh;
|
||||||
|
pointer-events: none;
|
||||||
|
transform: translate(100vw,100vh);
|
||||||
|
}
|
||||||
|
&.active{
|
||||||
|
position: relative;
|
||||||
|
opacity: 1;
|
||||||
|
flex: 1;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
pointer-events: auto;
|
||||||
|
transform: translate(0,0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.btn{
|
.btn{
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="addDetailsModal generalModel" ref="addDetailsModal"></div>
|
|
||||||
<a-modal
|
|
||||||
class="addDetails_modal generalModel fullScreen"
|
|
||||||
v-model:visible="addDetails"
|
|
||||||
:footer="null"
|
|
||||||
:get-container="() => $refs.addDetailsModal"
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
:maskClosable="false"
|
|
||||||
:centered="true"
|
|
||||||
:closable="false"
|
|
||||||
:destroyOnClose="true"
|
|
||||||
wrapClassName="#app"
|
|
||||||
:keyboard="false"
|
|
||||||
:mask="false"
|
|
||||||
>
|
|
||||||
<div class="generalModel_btn">
|
|
||||||
<div class="generalModel_closeIcon" @click.stop="cancelDsign()">
|
|
||||||
<svg width="100%" height="100%" viewBox="0 0 46 46" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx="23" cy="23" r="23" fill="white" fill-opacity="0.3"/>
|
|
||||||
<rect x="32.5063" y="12" width="3" height="29" rx="1.5" transform="rotate(45 32.5063 12)" fill="#000"/>
|
|
||||||
<rect x="34.6274" y="32.5059" width="3" height="29" rx="1.5" transform="rotate(135 34.6274 32.5059)" fill="#000"/>
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="addDetails_center">
|
|
||||||
<generalMiniCanvas :imgUrl="imgUrl" @submitBase64Data="submitBase64Data"></generalMiniCanvas>
|
|
||||||
</div>
|
|
||||||
<div></div>
|
|
||||||
</a-modal>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import { defineComponent, ref, reactive, watch, onMounted, nextTick, toRefs } from "vue";
|
|
||||||
import generalMiniCanvas from "../modules/generalMiniCanvas.vue";
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
generalMiniCanvas,
|
|
||||||
},
|
|
||||||
emits: ['setSloganData'],
|
|
||||||
setup(props,{emit}) {
|
|
||||||
let addDetail = reactive({
|
|
||||||
imgUrl:''
|
|
||||||
});
|
|
||||||
let addDetails = ref(false);
|
|
||||||
let init = (data,index)=>{
|
|
||||||
addDetails.value = true
|
|
||||||
addDetail.imgUrl = data.sketchString || data.path
|
|
||||||
}
|
|
||||||
let submitBase64Data = (data)=>{
|
|
||||||
emit('setSloganData',data)
|
|
||||||
cancelDsign()
|
|
||||||
}
|
|
||||||
let cancelDsign = ()=>{
|
|
||||||
addDetails.value = false
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...toRefs(addDetail),
|
|
||||||
addDetails,
|
|
||||||
init,
|
|
||||||
submitBase64Data,
|
|
||||||
cancelDsign,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {},
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.addDetailsModal{
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
.addDetails_modal {
|
|
||||||
.closeIcon {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
.addDetails_center{
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.exportCanvasBox_submit{
|
|
||||||
// margin-top: 2.4rem;
|
|
||||||
// text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -5,17 +5,16 @@
|
|||||||
<div class="canvasContent" ref="canvasContent">
|
<div class="canvasContent" ref="canvasContent">
|
||||||
<div class="content-bottom" ref="canvasContent">
|
<div class="content-bottom" ref="canvasContent">
|
||||||
<div class="contet">
|
<div class="contet">
|
||||||
<!-- :clothingImageUrl="selectDetail?.undividedLayerWithSinglePrint || selectDetail.undividedLayer || selectDetail.path" -->
|
<div class="canvas" :class="{'active': currentView === 'canvasEditor'}"@click.stop>
|
||||||
<div class="canvas" v-if="currentView === 'canvasEditor'" @click.stop>
|
|
||||||
<editCanvas v-if="canvasLoad" :config="canvasConfig"
|
<editCanvas v-if="canvasLoad" :config="canvasConfig"
|
||||||
@canvasInit="canvasInit"
|
@canvasInit="editSketchCanvasInit"
|
||||||
@changeCanvas="changeCanvas"
|
|
||||||
is-edit
|
is-edit
|
||||||
|
:clothingMinIOPath="selectDetail.minIOPath"
|
||||||
:clothingImageUrl="selectDetail.path"
|
:clothingImageUrl="selectDetail.path"
|
||||||
:clothingImageUrl2="selectDetail.undividedLayer"
|
:clothingImageUrl2="selectDetail.layersObject[0].maskUrl"
|
||||||
showFixedLayer
|
showFixedLayer
|
||||||
:canvasJSON="canvasJSON"
|
:canvasJSON="canvasJSON"
|
||||||
:otherData="otherData"
|
@canvasLoadJsonSuccess="canvasLoadJsonSuccess"
|
||||||
:clothing-image-opts="{
|
:clothing-image-opts="{
|
||||||
imageMode:'contains',
|
imageMode:'contains',
|
||||||
}"
|
}"
|
||||||
@@ -25,14 +24,8 @@
|
|||||||
<!-- <canvasContent ref="canvasContent"></canvasContent> -->
|
<!-- <canvasContent ref="canvasContent"></canvasContent> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="editFrontBack" v-if="currentView === 'redGreenExample'" @click.stop>
|
<div class="editFrontBack" v-if="currentView === 'redGreenExample'" @click.stop>
|
||||||
<!-- <editFrontBack
|
|
||||||
:patchData="frontBack"
|
|
||||||
:imgDomIndex="imgDomIndex"
|
|
||||||
|
|
||||||
ref="editFrontBack">
|
|
||||||
</editFrontBack> -->
|
|
||||||
<editCanvas v-if="canvasLoad" :config="canvasConfig"
|
<editCanvas v-if="canvasLoad" :config="canvasConfig"
|
||||||
@canvasInit="canvasInit"
|
@canvasInit="editFrontBackCanvasInit"
|
||||||
:enabledRedGreenMode="true"
|
:enabledRedGreenMode="true"
|
||||||
:clothingImageUrl="selectDetail.path"
|
:clothingImageUrl="selectDetail.path"
|
||||||
:redGreenImageUrl="frontBack.front[imgDomIndex].maskUrl"
|
:redGreenImageUrl="frontBack.front[imgDomIndex].maskUrl"
|
||||||
@@ -45,6 +38,9 @@
|
|||||||
ref="editCanvasBackFront">
|
ref="editCanvasBackFront">
|
||||||
</editCanvas>
|
</editCanvas>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="editSketch" v-if="currentView === 'editSketch'" @click.stop>
|
||||||
|
<generalMiniCanvas ref="generalMiniCanvas" :btnShow="false" :imgUrl="selectDetail.sketchString || selectDetail.path"></generalMiniCanvas>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="Finish">
|
<!-- <div class="Finish">
|
||||||
@@ -69,16 +65,25 @@ import { useI18n } from 'vue-i18n'
|
|||||||
import editCanvas from "@/component/Canvas/CanvasEditor/index.vue";
|
import editCanvas from "@/component/Canvas/CanvasEditor/index.vue";
|
||||||
import { formatTime,segmentImage,getMinioUrl } from "@/tool/util";
|
import { formatTime,segmentImage,getMinioUrl } from "@/tool/util";
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import generalMiniCanvas from "../../modules/generalMiniCanvas.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components:{
|
||||||
editCanvas
|
editCanvas,generalMiniCanvas
|
||||||
},
|
},
|
||||||
props:{
|
props:{
|
||||||
isEditPattern:{
|
isEditPattern:{
|
||||||
type:String,
|
type:String,
|
||||||
default:''
|
default:''
|
||||||
}
|
},
|
||||||
|
updateOtherLayers:{
|
||||||
|
type:Function,
|
||||||
|
default:()=>{}
|
||||||
|
},
|
||||||
|
sketchSize:{
|
||||||
|
type:Object,
|
||||||
|
default:()=>{}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -90,6 +95,7 @@ export default defineComponent({
|
|||||||
editCanvas:null as any,
|
editCanvas:null as any,
|
||||||
editCanvasBackFront:null as any,
|
editCanvasBackFront:null as any,
|
||||||
canvasContent:null as any,
|
canvasContent:null as any,
|
||||||
|
generalMiniCanvas:null as any,
|
||||||
})
|
})
|
||||||
const userDetail = computed(()=>{
|
const userDetail = computed(()=>{
|
||||||
return store.state.UserHabit.userDetail
|
return store.state.UserHabit.userDetail
|
||||||
@@ -130,14 +136,14 @@ export default defineComponent({
|
|||||||
if(detailData.currentView === 'canvasEditor'){
|
if(detailData.currentView === 'canvasEditor'){
|
||||||
sessionStorage.setItem('sketchEdit',detailDom.editCanvas.getJSON())
|
sessionStorage.setItem('sketchEdit',detailDom.editCanvas.getJSON())
|
||||||
canvasJSON = sessionStorage.getItem('frontBackEdit');
|
canvasJSON = sessionStorage.getItem('frontBackEdit');
|
||||||
}else{
|
}else if(detailData.currentView === 'redGreenExample'){
|
||||||
sessionStorage.setItem('frontBackEdit',detailDom.editCanvasBackFront.getJSON())
|
sessionStorage.setItem('frontBackEdit',detailDom.editCanvasBackFront.getJSON())
|
||||||
canvasJSON = sessionStorage.getItem('sketchEdit');
|
canvasJSON = sessionStorage.getItem('sketchEdit');
|
||||||
}
|
}
|
||||||
detailData.canvasLoad = false
|
// detailData.canvasLoad = false
|
||||||
detailData.currentView = str
|
detailData.currentView = str
|
||||||
if(canvasJSON){
|
if(canvasJSON){
|
||||||
detailData.canvasLoad = true
|
// detailData.canvasLoad = true
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
if(detailData.currentView === 'redGreenExample'){
|
if(detailData.currentView === 'redGreenExample'){
|
||||||
detailDom.editCanvas.loadJSON(canvasJSON)
|
detailDom.editCanvas.loadJSON(canvasJSON)
|
||||||
@@ -148,29 +154,51 @@ export default defineComponent({
|
|||||||
}else{
|
}else{
|
||||||
if(detailData.currentView === 'redGreenExample'){
|
if(detailData.currentView === 'redGreenExample'){
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
setCanvas(detailData.selectDetail?.undividedLayerWithSinglePrint || detailData.selectDetail.undividedLayer || detailData.selectDetail.path).then(()=>{
|
setCanvas(detailData.selectDetail.path).then(()=>{
|
||||||
detailData.canvasLoad = true
|
// detailData.canvasLoad = true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
setCanvas(detailData.frontBack.front[detailData.imgDomIndex].maskUrl).then(()=>{
|
setCanvas(detailData.frontBack.front[detailData.imgDomIndex].maskUrl).then(()=>{
|
||||||
detailData.canvasLoad = true
|
// detailData.canvasLoad = true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
|
const updateOtherLayers = (obj:any)=>{
|
||||||
if(!detailDom.editCanvas)return
|
if(!detailDom.editCanvas)return
|
||||||
return new Promise((res,reject)=>{
|
return new Promise(async (res,reject)=>{
|
||||||
detailDom.editCanvas.exportImage({isContainBg:false,isContainFixed:false}).then((rv)=>{
|
await detailDom?.editCanvas.updateOtherLayers(obj)
|
||||||
if(oldSelectDetail?.partialDesign)oldSelectDetail.partialDesign.partialDesignBase64 = rv
|
res('')
|
||||||
res('')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
|
||||||
|
// if(!detailDom.editCanvas)return
|
||||||
|
return new Promise(async (res,reject)=>{
|
||||||
|
await detailDom.editCanvas.exportImage({
|
||||||
|
isContainFixed:true,
|
||||||
|
width:props.sketchSize.width,
|
||||||
|
height:props.sketchSize.height,
|
||||||
|
}).then((rv)=>{
|
||||||
|
if(oldSelectDetail?.partialDesign)oldSelectDetail.partialDesign.partialDesignBase64 = rv
|
||||||
|
})
|
||||||
|
//包含平铺图层 single+overall模式的图
|
||||||
|
// await detailDom.editCanvas.exportImage({isContainFixed:true,isPrintTrimsNoRepeat:true,isPrintTrimsRepeat:true,isContainNormalLayer:false}).then((rv)=>{
|
||||||
|
// oldSelectDetail.undividedLayerWithSinglePrint = rv
|
||||||
|
// })
|
||||||
|
//不包含平铺图层overall模式的图
|
||||||
|
// await detailDom.editCanvas.exportImage({isContainFixed:true,isPrintTrimsNoRepeat:false,isPrintTrimsRepeat:true,isContainNormalLayer:false}).then((rv)=>{
|
||||||
|
// oldSelectDetail.undividedLayer = rv
|
||||||
|
// })
|
||||||
|
await setUndivideLayer()
|
||||||
|
res('')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getCanvasElement = ()=>{
|
||||||
|
if(!detailDom?.editCanvas)return ''
|
||||||
|
return detailDom?.editCanvas.exportExtraInfo();
|
||||||
}
|
}
|
||||||
const setFrontBackColor = (data:any)=>{
|
const setFrontBackColor = (data:any)=>{
|
||||||
detailDom.editFrontBack.setBackground(data)
|
detailDom.editFrontBack.setBackground(data)
|
||||||
@@ -180,11 +208,14 @@ export default defineComponent({
|
|||||||
let img = new Image()
|
let img = new Image()
|
||||||
img.onload = ()=>{
|
img.onload = ()=>{
|
||||||
let wH = [1,1]
|
let wH = [1,1]
|
||||||
let domHeight = detailDom.canvasContent.offsetHeight - 200
|
let domHeight = detailDom.canvasContent?.offsetHeight - 200
|
||||||
let imgHeight = img.height
|
let imgHeight = img.height
|
||||||
wH = [1,domHeight/imgHeight]
|
wH = [1,domHeight/imgHeight]
|
||||||
detailData.canvasConfig.width = img.width * wH[1]
|
// detailData.canvasConfig.width = img.width * wH[1]
|
||||||
detailData.canvasConfig.height = domHeight
|
// detailData.canvasConfig.height = domHeight
|
||||||
|
console.log(detailData.canvasConfig,'===============')
|
||||||
|
detailData.canvasConfig.width = img.width
|
||||||
|
detailData.canvasConfig.height = img.height
|
||||||
|
|
||||||
res('')
|
res('')
|
||||||
}
|
}
|
||||||
@@ -234,7 +265,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
|
|
||||||
const frontBackChange = (value:any)=>{
|
const frontBackChange = (value:any)=>{
|
||||||
let full = detailData.frontBack.front[detailData.imgDomIndex]?.undividedLayerWithSinglePrint || detailData.frontBack.front[detailData.imgDomIndex].undividedLayer || detailData.selectDetail.path
|
let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.path
|
||||||
let size = {
|
let size = {
|
||||||
...detailData.canvasConfig,
|
...detailData.canvasConfig,
|
||||||
}
|
}
|
||||||
@@ -255,28 +286,34 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
const canvasInit = (value:any)=>{
|
const editSketchCanvasInit = (value:any)=>{
|
||||||
detailData.canvasInstance = value
|
detailData.canvasInstance = value
|
||||||
detailData.getCanvasIfEdit.fun = getCanvasLength
|
detailData.getCanvasIfEdit.fun = getCanvasLength
|
||||||
detailData.isShowMark = false
|
detailData.isShowMark = false
|
||||||
|
console.log('初始化完成')
|
||||||
|
}
|
||||||
|
const editFrontBackCanvasInit = (value:any)=>{
|
||||||
|
detailData.canvasInstance = value
|
||||||
|
detailData.getCanvasIfEdit.fun = getCanvasLength
|
||||||
|
detailData.isShowMark = false
|
||||||
|
console.log('初始化完成')
|
||||||
}
|
}
|
||||||
const getCanvasLength = ()=>{
|
const getCanvasLength = ()=>{
|
||||||
return detailData.canvasInstance?.commandManager?.undoStack?.length
|
return detailData.canvasInstance?.commandManager?.undoStack?.length
|
||||||
}
|
}
|
||||||
const saveCanvas = async (type:string = '')=>{
|
const getCanvasJSON = ()=>{
|
||||||
if(type !== 'auto'){
|
if(!detailDom?.editCanvas)return ''
|
||||||
detailData.isShowMark = true
|
return detailDom?.editCanvas?.getJSON()
|
||||||
}
|
}
|
||||||
const index = detailData.designDetail.clothes.findIndex(item => item.id === detailData.selectDetail.id);
|
const saveCanvas = async (canvasData:any)=>{
|
||||||
|
const index = detailData.designDetail.clothes.findIndex(item => item.id === canvasData.id);
|
||||||
await new Promise<void>((resolve, reject) => {
|
await new Promise<void>((resolve, reject) => {
|
||||||
if(!detailDom?.editCanvas)return resolve()
|
let canvasJSON = JSON.parse(canvasData.canvasJSON)
|
||||||
let canvasJSON = detailDom?.editCanvas?.getJSON()
|
if(!canvasJSON)return resolve()
|
||||||
let canvasData = JSON.parse(canvasJSON)
|
// canvasData.canvas.objects.forEach((objectsItem:any) => {
|
||||||
if(!canvasData)return resolve()
|
// if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src)
|
||||||
canvasData.canvas.objects.forEach((objectsItem:any) => {
|
// });
|
||||||
if(objectsItem.type == 'image')objectsItem.minioUrl = getMinioUrl(objectsItem.src)
|
let blob = new Blob([JSON.stringify(canvasJSON)], { type: "application/json" });
|
||||||
});
|
|
||||||
let blob = new Blob([JSON.stringify(canvasData)], { type: "application/json" });
|
|
||||||
let formData = new FormData();
|
let formData = new FormData();
|
||||||
formData.append("file", blob, "data.json");
|
formData.append("file", blob, "data.json");
|
||||||
formData.append("designItemDetailId", detailData.selectDetail.id);
|
formData.append("designItemDetailId", detailData.selectDetail.id);
|
||||||
@@ -297,12 +334,52 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let time = null as any
|
// let time = null as any
|
||||||
const changeCanvas = ()=>{
|
// const changeCanvas = ()=>{
|
||||||
clearTimeout(time)
|
// clearTimeout(time)
|
||||||
time = setTimeout(()=>{
|
// time = setTimeout(()=>{
|
||||||
saveCanvas('auto')
|
// saveCanvas('auto')
|
||||||
},3000)
|
// },3000)
|
||||||
|
// }
|
||||||
|
const canvasLoadJsonSuccess = async ()=>{
|
||||||
|
let otherData = await props.updateOtherLayers()
|
||||||
|
|
||||||
|
await updateOtherLayers(otherData)
|
||||||
|
await setUndivideLayer()
|
||||||
|
}
|
||||||
|
const setUndivideLayer = async ()=>{
|
||||||
|
await new Promise<void>(async (resolve, reject) => {
|
||||||
|
// if(!detailData.selectDetail.undividedLayerColor){
|
||||||
|
await detailDom.editCanvas.exportImage({
|
||||||
|
isContainFixed:true,
|
||||||
|
isPrintTrimsRepeat:false,
|
||||||
|
isPrintTrimsNoRepeat:false,
|
||||||
|
isContainNormalLayer:false,
|
||||||
|
width:props.sketchSize.width,
|
||||||
|
height:props.sketchSize.height}).then((rv)=>{
|
||||||
|
detailData.selectDetail.undividedLayerColor = rv
|
||||||
|
})
|
||||||
|
// }
|
||||||
|
// if(!detailData.selectDetail.undividedLayer){
|
||||||
|
await detailDom.editCanvas.exportImage({
|
||||||
|
isContainFixed:true,
|
||||||
|
isPrintTrimsNoRepeat:false,
|
||||||
|
isPrintTrimsRepeat:true,
|
||||||
|
isContainNormalLayer:false,
|
||||||
|
width:props.sketchSize.width,
|
||||||
|
height:props.sketchSize.height,
|
||||||
|
}).then((rv)=>{
|
||||||
|
console.log(rv,'======')
|
||||||
|
detailData.selectDetail.undividedLayer = rv
|
||||||
|
})
|
||||||
|
// }
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitBase64Data = ()=>{
|
||||||
|
return detailDom.generalMiniCanvas.submitBase64Data()
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeUnmount(()=>{
|
onBeforeUnmount(()=>{
|
||||||
@@ -322,6 +399,12 @@ export default defineComponent({
|
|||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
nextTick(async ()=>{
|
nextTick(async ()=>{
|
||||||
// detailData.currentView = 'canvasEditor'
|
// detailData.currentView = 'canvasEditor'
|
||||||
|
const sessionCanvasList = sessionStorage.getItem('canvasList');
|
||||||
|
const canvasList = sessionCanvasList ? JSON.parse(sessionCanvasList) : []
|
||||||
|
let canvasIndex = canvasList.findIndex(item => item.id === detailData.selectDetail.id);
|
||||||
|
if(canvasIndex>1){
|
||||||
|
detailData.canvasJSON = canvasList[canvasIndex].canvasJSON
|
||||||
|
}
|
||||||
if(detailData.selectDetail.canvasId){
|
if(detailData.selectDetail.canvasId){
|
||||||
detailData.isShowMark = true
|
detailData.isShowMark = true
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
@@ -339,7 +422,7 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
setCanvas(detailData.selectDetail?.undividedLayerWithSinglePrint || detailData.selectDetail.undividedLayer || detailData.selectDetail.path).then(()=>{
|
setCanvas(detailData.selectDetail.path).then(()=>{
|
||||||
detailData.canvasLoad = true
|
detailData.canvasLoad = true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -351,9 +434,14 @@ export default defineComponent({
|
|||||||
privewDetail,
|
privewDetail,
|
||||||
setFrontBackColor,
|
setFrontBackColor,
|
||||||
frontBackChange,
|
frontBackChange,
|
||||||
canvasInit,
|
editSketchCanvasInit,
|
||||||
|
editFrontBackCanvasInit,
|
||||||
saveCanvas,
|
saveCanvas,
|
||||||
changeCanvas,
|
getCanvasElement,
|
||||||
|
updateOtherLayers,
|
||||||
|
canvasLoadJsonSuccess,
|
||||||
|
submitBase64Data,
|
||||||
|
getCanvasJSON,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
@@ -434,7 +522,15 @@ export default defineComponent({
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
.canvas,.editFrontBack{
|
.canvas{
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
&.active{
|
||||||
|
opacity: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.canvas,.editFrontBack,.editSketch{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import SelectImages from '@/component/common/SelectImages.vue'
|
|||||||
|
|
||||||
import upload from './upload.vue'
|
import upload from './upload.vue'
|
||||||
import pallet from './pallet.vue'
|
import pallet from './pallet.vue'
|
||||||
|
import { select } from 'three/tsl';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components:{
|
||||||
upload,pallet,SelectImages
|
upload,pallet,SelectImages
|
||||||
@@ -104,8 +105,12 @@ export default defineComponent({
|
|||||||
newVal.name = data.name
|
newVal.name = data.name
|
||||||
newVal.tcx = data.tcx
|
newVal.tcx = data.tcx
|
||||||
colorData.colorList.list[colorData.selectDetail.id][colorData.colorList.index] = newVal
|
colorData.colorList.list[colorData.selectDetail.id][colorData.colorList.index] = newVal
|
||||||
|
data.rgba = newVal.rgba
|
||||||
|
if(newVal.gradient){
|
||||||
|
data.gradient = newVal.gradient
|
||||||
|
}
|
||||||
let value = {
|
let value = {
|
||||||
data:newVal,
|
data:data,
|
||||||
str:'color'
|
str:'color'
|
||||||
}
|
}
|
||||||
store.commit('DesignDetail/setNewDetail',value)
|
store.commit('DesignDetail/setNewDetail',value)
|
||||||
@@ -132,16 +137,14 @@ export default defineComponent({
|
|||||||
item = colorData.allBoardData.colorBoards[index]
|
item = colorData.allBoardData.colorBoards[index]
|
||||||
let color = colorData.allBoardData.colorBoards?.[index]
|
let color = colorData.allBoardData.colorBoards?.[index]
|
||||||
if(!color?.rgba && color?.rgbValue)color.rgba = color.rgbValue
|
if(!color?.rgba && color?.rgbValue)color.rgba = color.rgbValue
|
||||||
|
|
||||||
if(
|
if(
|
||||||
colorData.allBoardData.colorBoards?.[index] &&
|
colorData.allBoardData.colorBoards?.[index] &&
|
||||||
colorData.selectDetail.color.rgba?.r == color?.rgba?.r &&
|
colorData.selectDetail.color.rgba?.r == color?.rgba?.r &&
|
||||||
colorData.selectDetail.color.rgba?.g == color?.rgba?.g &&
|
colorData.selectDetail.color.rgba?.g == color?.rgba?.g &&
|
||||||
colorData.selectDetail.color.rgba?.b == color?.rgba?.b &&
|
colorData.selectDetail.color.rgba?.b == color?.rgba?.b ||
|
||||||
JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient)
|
(JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(color?.gradient) && JSON.stringify(colorData.selectDetail.color.gradient))
|
||||||
&& colorData.selectDetail.color.rgba?.r
|
&& colorData.selectDetail.color.rgba?.r
|
||||||
){
|
){
|
||||||
console.log('---',index)
|
|
||||||
isNoSelect = true
|
isNoSelect = true
|
||||||
colorData.selectColor = item
|
colorData.selectColor = item
|
||||||
colorData.colorList.index = index
|
colorData.colorList.index = index
|
||||||
@@ -190,52 +193,11 @@ export default defineComponent({
|
|||||||
colorData.colorList.index = num
|
colorData.colorList.index = num
|
||||||
colorData.colorList.list[newVal][num] = item
|
colorData.colorList.list[newVal][num] = item
|
||||||
}
|
}
|
||||||
|
// let newData = colorData.selectDetail?.newDetail?.color
|
||||||
// for (let index = 0; index < 9; index++) {
|
// console.log(newData,colorData.selectColor)
|
||||||
// colorData.allBoardData.colorBoards
|
// if(newData){
|
||||||
// let item:any = {}
|
// newData.hex = rgbaToHex([newData.rgba.r,newData.rgba.g,newData.rgba.b])
|
||||||
// item = colorData.allBoardData.colorBoards[index]
|
// colorData.selectColor = newData
|
||||||
// if(
|
|
||||||
// colorData.allBoardData.colorBoards?.[index] &&
|
|
||||||
// colorData.selectDetail.color.rgba?.r == colorData.allBoardData.colorBoards?.[index]?.rgba?.r &&
|
|
||||||
// colorData.selectDetail.color.rgba?.g == colorData.allBoardData.colorBoards?.[index]?.rgba?.g &&
|
|
||||||
// colorData.selectDetail.color.rgba?.b == colorData.allBoardData.colorBoards?.[index]?.rgba?.b &&
|
|
||||||
// JSON.stringify(colorData.selectDetail.color.gradient) == JSON.stringify(colorData.allBoardData.colorBoards?.[index]?.gradient)
|
|
||||||
// && colorData.selectDetail.color.rgba?.r
|
|
||||||
// ){
|
|
||||||
// console.log(13212)
|
|
||||||
// if(!isOneChecked){
|
|
||||||
// isOneChecked = true
|
|
||||||
// if(colorData.allBoardData.colorBoards?.[index].gradient){
|
|
||||||
// item.gradient = colorData.allBoardData.colorBoards?.[index].gradient
|
|
||||||
// }
|
|
||||||
// colorData.selectColor = item
|
|
||||||
// colorData.colorList.index = index
|
|
||||||
// }
|
|
||||||
// }else if(colorData.selectDetail.color.rgba?.r){
|
|
||||||
// if(!isNoSelect){
|
|
||||||
// item = {
|
|
||||||
// hex:rgbaToHex([colorData.selectDetail.color.rgba.r,colorData.selectDetail.color.rgba.g,colorData.selectDetail.color.rgba.b]),
|
|
||||||
// id:colorData.selectDetail.color.id,
|
|
||||||
// rgba:{
|
|
||||||
// r:colorData.selectDetail.color.rgba.r,
|
|
||||||
// g:colorData.selectDetail.color.rgba.g,
|
|
||||||
// b:colorData.selectDetail.color.rgba.b,
|
|
||||||
// },
|
|
||||||
// tcx:colorData.selectDetail.color.tcx,
|
|
||||||
// name:colorData.selectDetail.color.name,
|
|
||||||
// }
|
|
||||||
// if(colorData.selectDetail.color.gradient){
|
|
||||||
// item.gradient = colorData.selectDetail.color.gradient
|
|
||||||
// }
|
|
||||||
// colorData.colorList.index = index
|
|
||||||
// colorData.selectColor = item
|
|
||||||
// isNoSelect = true
|
|
||||||
// }else{
|
|
||||||
// item = {}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// colorData.colorList.list[newVal].push(item)
|
|
||||||
// }
|
// }
|
||||||
},{immediate: true})
|
},{immediate: true})
|
||||||
const selectImgItem = ()=>{
|
const selectImgItem = ()=>{
|
||||||
@@ -281,7 +243,6 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const handleShowListChange=(val:boolean)=>{
|
const handleShowListChange=(val:boolean)=>{
|
||||||
console.log('val',val)
|
|
||||||
showLibrary.value = !val
|
showLibrary.value = !val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="detailLeft">
|
<div class="detailLeft">
|
||||||
<sketch v-show="currentDetailType == 'sketch'" ref="sketch" @addDetail="addDetail"></sketch>
|
<sketch v-show="currentDetailType == 'sketch'" ref="sketch" @addDetail="addDetail"></sketch>
|
||||||
<print v-show="currentDetailType == 'print'"></print>
|
<print v-show="currentDetailType == 'print'"></print>
|
||||||
<color v-if="currentDetailType == 'color'"></color>
|
<color v-if="currentDetailType == 'color'" :key="detailLeftColorKey"></color>
|
||||||
<element v-show="currentDetailType == 'element'"></element>
|
<element v-show="currentDetailType == 'element'"></element>
|
||||||
<accessory v-show="currentDetailType == 'accessory'"></accessory>
|
<accessory v-show="currentDetailType == 'accessory'"></accessory>
|
||||||
<models v-show="currentDetailType == 'models'"></models>
|
<models v-show="currentDetailType == 'models'"></models>
|
||||||
@@ -26,6 +26,12 @@ export default defineComponent({
|
|||||||
components:{
|
components:{
|
||||||
sketch,print,color,element,models,accessory
|
sketch,print,color,element,models,accessory
|
||||||
},
|
},
|
||||||
|
props:{
|
||||||
|
detailLeftColorKey:{
|
||||||
|
type:Number,
|
||||||
|
default:0,
|
||||||
|
},
|
||||||
|
},
|
||||||
emit:['addDetail'],
|
emit:['addDetail'],
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ export default defineComponent({
|
|||||||
file.designType = file?.resData?.designType
|
file.designType = file?.resData?.designType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// store.commit('DesignDetail/setNewDetail',file.resData)
|
|
||||||
emit('selectImgItem',file)
|
emit('selectImgItem',file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,6 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
const selectImgItem = (file:any)=>{
|
const selectImgItem = (file:any)=>{
|
||||||
// let data = JSON.parse(JSON.stringify(file))
|
// let data = JSON.parse(JSON.stringify(file))
|
||||||
// store.commit('DesignDetail/setNewDetail',file)
|
|
||||||
emit('selectImgItem',file)
|
emit('selectImgItem',file)
|
||||||
}
|
}
|
||||||
const upFileUploadChange = (data:any)=>{
|
const upFileUploadChange = (data:any)=>{
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
const selectImgItem = (file:any)=>{
|
const selectImgItem = (file:any)=>{
|
||||||
// let data = JSON.parse(JSON.stringify(file))
|
// let data = JSON.parse(JSON.stringify(file))
|
||||||
// store.commit('DesignDetail/setNewDetail',file)
|
|
||||||
emit('selectImgItem',file)
|
emit('selectImgItem',file)
|
||||||
}
|
}
|
||||||
const setUploadImgList = (list:any)=>{
|
const setUploadImgList = (list:any)=>{
|
||||||
|
|||||||
@@ -16,20 +16,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="printElementListBorder" :class="{'single':stateOverallSingle == 'single'}">
|
<div class="printElementListBorder single">
|
||||||
<div class="printElementList" ref="printElementList" :style="{height:stateOverallSingle == 'overall'?'14rem':'10rem'}">
|
<div class="printElementList" ref="printElementList" :style="{height:'10rem'}">
|
||||||
<div class="itemList" :style="{width:stateOverallSingle == 'single'?(prentWidth || 0) : '100%'}">
|
<div class="itemList" :style="{width:(prentWidth || 0)}">
|
||||||
<div class="imgItem"
|
<div class="imgItem"
|
||||||
v-if="stateOverallSingle == 'single'"
|
v-for="item,index in printStyleList[type][stateOverallSingle]"
|
||||||
v-for="item in printStyleList[type][stateOverallSingle]"
|
|
||||||
:key="item"
|
:key="item"
|
||||||
|
:class="{active:stateOverallSingle == 'overall' && index == imgDomIndex}"
|
||||||
@mousedown.stop="designMousedown(getMousePosition($event,false),item.uniqueId,'disLike')"
|
@mousedown.stop="designMousedown(getMousePosition($event,false),item.uniqueId,'disLike')"
|
||||||
@touchstart.passive="designMousedown(getMousePosition($event,true),item.uniqueId,'disLike')"
|
@touchstart.passive="designMousedown(getMousePosition($event,true),item.uniqueId,'disLike')"
|
||||||
|
@click.stop="overallSetIndex(item)"
|
||||||
>
|
>
|
||||||
<img :src="item.path" alt="">
|
<img :src="item.path" alt="">
|
||||||
<i class="fi fi-rr-trash" @click="navDelete(item)"></i>
|
<i class="fi fi-rr-trash" @click.stop="navDelete(item)"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="imgItem"
|
<!-- <div class="imgItem"
|
||||||
v-if="stateOverallSingle == 'overall'"
|
v-if="stateOverallSingle == 'overall'"
|
||||||
v-for="item in printStyleList[type][stateOverallSingle]"
|
v-for="item in printStyleList[type][stateOverallSingle]"
|
||||||
:key="item"
|
:key="item"
|
||||||
@@ -37,31 +38,49 @@
|
|||||||
>
|
>
|
||||||
<img :src="item.path" alt="">
|
<img :src="item.path" alt="">
|
||||||
<i class="fi fi-rr-trash" @click="navDelete(item)"></i>
|
<i class="fi fi-rr-trash" @click="navDelete(item)"></i>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="stateOverallSingle != 'single'" class="habit_System_Designer">
|
<div v-if="imgDomIndex >= 0" v-show="stateOverallSingle != 'single'" class="habit_System_Designer">
|
||||||
<div class="habit_System_Designer_text">{{ $t('DesignPrintOperation.Scale') }}</div>
|
<!-- <a-slider id="system_silder"
|
||||||
<a-slider id="system_silder"
|
|
||||||
class="system_silder"
|
class="system_silder"
|
||||||
:min="20"
|
:min="20"
|
||||||
:max="1000"
|
:max="1000"
|
||||||
v-model:value="systemDesignerPercentage"
|
v-model:value="systemDesignerPercentage"
|
||||||
:tip-formatter="formatter"
|
:tip-formatter="formatter"
|
||||||
>
|
>
|
||||||
</a-slider>
|
</a-slider> -->
|
||||||
|
<a-popover
|
||||||
|
trigger="click"
|
||||||
|
destroyTooltipOnHide
|
||||||
|
:title="t('Canvas.repeatSetting')"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<repeat-setting
|
||||||
|
:object="printStyleList[type].overall[imgDomIndex]"
|
||||||
|
@inputFillAngle="inputFillAngle"
|
||||||
|
@inputFillOffset="inputFillOffset"
|
||||||
|
@inputFillScale="inputFillScale"
|
||||||
|
:sketchPath="selectDetail.path"
|
||||||
|
@inputFill_Gap="
|
||||||
|
(x, y) => inputFill_Gap(x, y)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<div class="btn">
|
||||||
|
<SvgIcon name="overallMore" size="20" />
|
||||||
|
</div>
|
||||||
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
<div class="editPrintElementBox">
|
<div class="editPrintElementBox">
|
||||||
<div class="designOpenrtion_centent" id="designOpenrtionCentent">
|
<div class="designOpenrtion_centent" id="designOpenrtionCentent">
|
||||||
<!-- <div class="designOpenrtion_imgMask" :style="sketch"> -->
|
<!-- <div class="designOpenrtion_imgMask" :style="sketch"> -->
|
||||||
<div class="designOpenrtion_imgMask">
|
<div class="designOpenrtion_imgMask">
|
||||||
<div class="designOpenrtion_print">
|
<div class="designOpenrtion_print" v-if="stateOverallSingle == 'single'">
|
||||||
<div
|
<div
|
||||||
v-for="item,index in printStyleList[type][stateOverallSingle]"
|
v-for="item,index in printStyleList[type][stateOverallSingle]"
|
||||||
:key="item"
|
:key="item"
|
||||||
v-if="stateOverallSingle == 'single'"
|
:style="{...item?.pattern?.style,opacity:item?.object?.opacity || 1}"
|
||||||
:style="item?.pattern?.style"
|
|
||||||
@mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))"
|
@mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))"
|
||||||
class="modal_imgItem"
|
class="modal_imgItem"
|
||||||
ref="content"
|
ref="content"
|
||||||
@@ -70,9 +89,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <img :src="selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg"> -->
|
<!-- <img :src="selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg"> -->
|
||||||
<img :src="selectDetail?.undividedLayer?selectDetail.undividedLayer:selectDetail.path" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true">
|
<img :src="stateOverallSingle == 'single'?(selectDetail.undividedLayer||selectDetail.path):(selectDetail.undividedLayerColor || selectDetail.path)" alt="" class="designOpenrtion_sketch" ref="sketchImg" @load="()=>isSketchLoad = true">
|
||||||
<div class="designOpenrtion_btn">
|
<img :src="selectDetail.sketchMask" alt="" class="designOpenrtion_sketchMask" ref="sketchMask">
|
||||||
<ul v-if="stateOverallSingle == 'single'" v-for="item,index in printStyleList[type][stateOverallSingle]" :key="item" :class="{active:item?.pattern.designOpenrtionBtn?item?.pattern.designOpenrtionBtn:false}" class="designOpenrtion_Mousingle" :style="item?.pattern.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
|
<div class="designOpenrtion_btn" v-if="stateOverallSingle == 'single'" >
|
||||||
|
<ul v-for="item,index in printStyleList[type][stateOverallSingle]" :key="item" :class="{active:item?.pattern.designOpenrtionBtn?item?.pattern.designOpenrtionBtn:false}" class="designOpenrtion_Mousingle" :style="item?.pattern.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
|
||||||
<li class="designOpenrtion_btn_top" @mousedown.stop="itemSizeMousedown('top',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('top',getMousePosition($event,true))"></li>
|
<li class="designOpenrtion_btn_top" @mousedown.stop="itemSizeMousedown('top',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('top',getMousePosition($event,true))"></li>
|
||||||
<li class="designOpenrtion_btn_bottom" @mousedown.stop="itemSizeMousedown('bottom',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('bottom',getMousePosition($event,true))"></li>
|
<li class="designOpenrtion_btn_bottom" @mousedown.stop="itemSizeMousedown('bottom',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('bottom',getMousePosition($event,true))"></li>
|
||||||
<li class="designOpenrtion_btn_left" @mousedown.stop="itemSizeMousedown('left',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('left',getMousePosition($event,true))"></li>
|
<li class="designOpenrtion_btn_left" @mousedown.stop="itemSizeMousedown('left',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('left',getMousePosition($event,true))"></li>
|
||||||
@@ -82,12 +102,15 @@
|
|||||||
<img src="../../../assets/images/homePage/cuowu.svg" alt="">
|
<img src="../../../assets/images/homePage/cuowu.svg" alt="">
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div v-show="stateOverallSingle != 'single'"></div>
|
<!-- <div v-show="stateOverallSingle != 'single'"></div>
|
||||||
<ul v-if="stateOverallSingle != 'single' && printStyleList[type][stateOverallSingle][0]" class="designOpenrtion_Mouoverall active" :style="'left:'+printStyleList[type][stateOverallSingle][0]?.pattern?.style?.left+';top:'+printStyleList[type][stateOverallSingle][0]?.pattern?.style?.top+';'" @mousedown.stop="itemMoveMousedown(0,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(0,getMousePosition($event,true))">
|
<ul v-if="stateOverallSingle != 'single' && printStyleList[type][stateOverallSingle][0]" class="designOpenrtion_Mouoverall active" :style="'left:'+printStyleList[type][stateOverallSingle][0]?.pattern?.style?.left+';top:'+printStyleList[type][stateOverallSingle][0]?.pattern?.style?.top+';'" @mousedown.stop="itemMoveMousedown(0,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(0,getMousePosition($event,true))">
|
||||||
<i class="fi fi-rr-arrows animtion1"></i>
|
<i class="fi fi-rr-arrows animtion1"></i>
|
||||||
<i class="fi fi-rr-arrows animtion2"></i>
|
<i class="fi fi-rr-arrows animtion2"></i>
|
||||||
<li class="designOpenrtion_rotote" v-rotote.stop="[0,printStyleList[type][stateOverallSingle][0]?.pattern?.transform,type]"></li>
|
<li class="designOpenrtion_rotote" v-rotote.stop="[0,printStyleList[type][stateOverallSingle][0]?.pattern?.transform,type]"></li>
|
||||||
</ul>
|
</ul> -->
|
||||||
|
</div>
|
||||||
|
<div class="designOpenrtion_pingpu" v-else>
|
||||||
|
<pingpu :list="printStyleList[type].overall" :width="sketchSize.width" :height="sketchSize.height" ref="pingpuRef" @change-canvas="updateCanvas"></pingpu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,20 +129,31 @@ import { defineComponent,computed,ref,onMounted,nextTick,watch,toRefs, reactive,
|
|||||||
// import setDesignItem from '@/component/Detail/setDesignItem2.vue'
|
// import setDesignItem from '@/component/Detail/setDesignItem2.vue'
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import { getMousePosition } from "@/tool/mdEvent";
|
import { getMousePosition } from "@/tool/mdEvent";
|
||||||
|
import { sketchToMask } from "@/tool/util";
|
||||||
|
import pingpu from '@/component/Canvas/OverallCanvas/index.vue'
|
||||||
|
import RepeatSetting from "./overallSetting/RepeatSetting.vue";
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components:{
|
||||||
|
pingpu,RepeatSetting
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'print',
|
default: 'print',
|
||||||
}
|
},
|
||||||
|
sketchSize:{
|
||||||
|
type:Object,
|
||||||
|
default:()=>{}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
|
const { t } = useI18n()
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const editPrintElementDom = reactive({
|
const editPrintElementDom = reactive({
|
||||||
imgDom:null as any,
|
imgDom:null as any,
|
||||||
sketchImg:null as any,
|
sketchImg:null as any,
|
||||||
|
pingpuRef:null as any,
|
||||||
})
|
})
|
||||||
const editPrintElementData = reactive({
|
const editPrintElementData = reactive({
|
||||||
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
|
selectDetail:computed(()=>store.state.DesignDetail.selectDetail),
|
||||||
@@ -135,9 +169,9 @@ export default defineComponent({
|
|||||||
single:[],
|
single:[],
|
||||||
}
|
}
|
||||||
} as any,
|
} as any,
|
||||||
stateOverallSingle:'single',
|
stateOverallSingle:'single' as any,
|
||||||
type:props.type,
|
type:props.type,
|
||||||
imgDomIndex:0,
|
imgDomIndex:-1,
|
||||||
direction:'',//判断点的那条边
|
direction:'',//判断点的那条边
|
||||||
printZIndex:2,//印花优先级
|
printZIndex:2,//印花优先级
|
||||||
sketchWH:{
|
sketchWH:{
|
||||||
@@ -149,6 +183,13 @@ export default defineComponent({
|
|||||||
printElementList:null as any,
|
printElementList:null as any,
|
||||||
isSketchLoad:false,
|
isSketchLoad:false,
|
||||||
})
|
})
|
||||||
|
const ACTIONS = {
|
||||||
|
ADD: "add",
|
||||||
|
UPDATE: "update",
|
||||||
|
DELETE: "delete",
|
||||||
|
SELECT: "select",
|
||||||
|
SORT: "sort",
|
||||||
|
};
|
||||||
const collItemSize = reactive({
|
const collItemSize = reactive({
|
||||||
collValue:18,
|
collValue:18,
|
||||||
num:1,
|
num:1,
|
||||||
@@ -168,13 +209,14 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const setOveralSingle = ()=>{
|
const setOveralSingle = ()=>{
|
||||||
|
|
||||||
setItemPosition()
|
setItemPosition()
|
||||||
}
|
}
|
||||||
const formatter = (value:any)=>{
|
const formatter = (value:any)=>{
|
||||||
return `${value}%`;
|
return `${value}%`;
|
||||||
}
|
}
|
||||||
const deletePrint = ()=>{
|
const deletePrint = ()=>{
|
||||||
editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle].splice(editPrintElementData.imgDomIndex,1)
|
if(editPrintElementData.imgDomIndex>-1)editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle].splice(editPrintElementData.imgDomIndex,1)
|
||||||
}
|
}
|
||||||
const setScaleLocation:any = (item:any)=>{
|
const setScaleLocation:any = (item:any)=>{
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@@ -215,6 +257,7 @@ export default defineComponent({
|
|||||||
path:data.url,
|
path:data.url,
|
||||||
priority:editPrintElementData.printZIndex,
|
priority:editPrintElementData.printZIndex,
|
||||||
scale,
|
scale,
|
||||||
|
globalCompositeOperation:'',
|
||||||
}
|
}
|
||||||
getItemPosition(item)
|
getItemPosition(item)
|
||||||
setItemPosition()
|
setItemPosition()
|
||||||
@@ -249,7 +292,9 @@ export default defineComponent({
|
|||||||
path:item.path,
|
path:item.path,
|
||||||
minIOPath:item.minIOPath,
|
minIOPath:item.minIOPath,
|
||||||
ifSingle:!!item.ifSingle,
|
ifSingle:!!item.ifSingle,
|
||||||
|
globalCompositeOperation:'',
|
||||||
}
|
}
|
||||||
|
if(item.object)value.object = item.object
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
if(editPrintElementData.printStyleList[props.type].single.length>0){
|
if(editPrintElementData.printStyleList[props.type].single.length>0){
|
||||||
@@ -282,7 +327,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
const getItemPosition = (item:any)=>{
|
const getItemPosition = (item:any)=>{
|
||||||
let left,top
|
let left,top
|
||||||
|
|
||||||
if(item.ifSingle){
|
if(item.ifSingle){
|
||||||
//single
|
//single
|
||||||
left = item.location[0] / editPrintElementData.sketchWH.scale[0]
|
left = item.location[0] / editPrintElementData.sketchWH.scale[0]
|
||||||
@@ -312,13 +356,40 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
editPrintElementData.printZIndex++
|
editPrintElementData.printZIndex++
|
||||||
item.pattern = pattern
|
item.pattern = pattern
|
||||||
|
|
||||||
|
if(item.object){
|
||||||
|
|
||||||
|
}else{
|
||||||
|
item.object = {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
scaleX: 1,
|
||||||
|
scaleY: 1,
|
||||||
|
opacity: 1,
|
||||||
|
angle: 0,
|
||||||
|
flipX: false,
|
||||||
|
flipY: false,
|
||||||
|
blendMode: "multiply",
|
||||||
|
gapX: 0,
|
||||||
|
gapY: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
if(item.ifSingle){
|
if(item.ifSingle){
|
||||||
editPrintElementData.printStyleList[props.type].single.push(item)
|
editPrintElementData.printStyleList[props.type].single.push(item)
|
||||||
}else{
|
}else{
|
||||||
editPrintElementData.printStyleList[props.type].overall = []
|
item.token = Date.now().toString() + (editPrintElementData.printStyleList[props.type].overall.length + '')
|
||||||
|
// editPrintElementData.printStyleList[props.type].overall = []
|
||||||
editPrintElementData.printStyleList[props.type].overall.push(item)
|
editPrintElementData.printStyleList[props.type].overall.push(item)
|
||||||
}
|
setTimeout(()=>{
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.ADD,
|
||||||
|
data: item,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const setPosition = ()=>{
|
const setPosition = ()=>{
|
||||||
nextTick(()=>{
|
nextTick(()=>{
|
||||||
@@ -337,16 +408,16 @@ export default defineComponent({
|
|||||||
if(!editPrintElementData.selectDetail.printObject.prints)return
|
if(!editPrintElementData.selectDetail.printObject.prints)return
|
||||||
let state = true
|
let state = true
|
||||||
// editPrintElementData.stateOverallSingle = 'single'
|
// editPrintElementData.stateOverallSingle = 'single'
|
||||||
let arr:any = editPrintElementData.selectDetail.printObject.prints
|
let arr:any = editPrintElementData.selectDetail.newDetail?.print || editPrintElementData.selectDetail.printObject.prints
|
||||||
if(props.type == 'element'){
|
if(props.type == 'element'){
|
||||||
arr = editPrintElementData.selectDetail.trims.prints
|
arr = editPrintElementData.selectDetail.newDetail?.element || editPrintElementData.selectDetail.trims.prints
|
||||||
}
|
}
|
||||||
if(editPrintElementData.selectDetail.newDetail?.[editPrintElementData.currentDetailType]){
|
if(editPrintElementData.selectDetail.newDetail?.[editPrintElementData.currentDetailType]){
|
||||||
arr = editPrintElementData.selectDetail.newDetail[editPrintElementData.currentDetailType]
|
arr = editPrintElementData.selectDetail.newDetail[editPrintElementData.currentDetailType]
|
||||||
}
|
}
|
||||||
if(arr && arr.length > 0){
|
if(arr && arr.length > 0){
|
||||||
arr.forEach((item:any)=>{
|
arr.forEach((item:any)=>{
|
||||||
if(!item.ifSingle && arr.length == 1){
|
if(!item.ifSingle){
|
||||||
editPrintElementData.stateOverallSingle = 'overall',
|
editPrintElementData.stateOverallSingle = 'overall',
|
||||||
state = false
|
state = false
|
||||||
}
|
}
|
||||||
@@ -377,15 +448,42 @@ export default defineComponent({
|
|||||||
addPrintELement(newVal)
|
addPrintELement(newVal)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
watch(()=>((editPrintElementData.selectDetail?.undividedLayer || editPrintElementData.selectDetail?.id)),(newVal)=>{
|
watch(()=>((editPrintElementData.selectDetail?.id)),(newVal)=>{
|
||||||
if(!newVal)return
|
if(!newVal)return
|
||||||
editPrintElementData.isSketchLoad = false,
|
editPrintElementData.isSketchLoad = false,
|
||||||
editPrintElementData.printStyleList[props.type] = {
|
editPrintElementData.printStyleList[props.type] = {
|
||||||
single:[],
|
single:[],
|
||||||
overall:[],
|
overall:[],
|
||||||
}
|
}
|
||||||
|
if(!editPrintElementData.selectDetail.sketchMask){
|
||||||
|
sketchToMask(editPrintElementData.selectDetail?.layersObject[0].maskUrl).then((res:any)=>{
|
||||||
|
editPrintElementData.selectDetail.sketchMask = res
|
||||||
|
})
|
||||||
|
}
|
||||||
setPosition()
|
setPosition()
|
||||||
},{immediate: true,})
|
},{immediate: true,})
|
||||||
|
watch(()=>editPrintElementData.stateOverallSingle,(newVal)=>{
|
||||||
|
let arr = editPrintElementData.printStyleList[props.type][newVal]
|
||||||
|
if(arr.length > 0){
|
||||||
|
editPrintElementData.imgDomIndex = 0
|
||||||
|
if(newVal == 'overall'){
|
||||||
|
arr.forEach((item:any,index:number) => {
|
||||||
|
item.id_ = index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
editPrintElementData.imgDomIndex = -1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
watch(()=>editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle].length,(newVal)=>{
|
||||||
|
if(newVal > 0){
|
||||||
|
if(editPrintElementData.imgDomIndex < 0)editPrintElementData.imgDomIndex = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const addOverallToCanvas = ()=>{
|
||||||
|
|
||||||
|
editPrintElementDom.pingpuRef
|
||||||
|
}
|
||||||
//设置移动
|
//设置移动
|
||||||
const itemMoveMousedown = (index:number,event:any)=>{
|
const itemMoveMousedown = (index:number,event:any)=>{
|
||||||
if (event.target.tagName === 'IMG' || event.target.nodeName === 'IMG')return
|
if (event.target.tagName === 'IMG' || event.target.nodeName === 'IMG')return
|
||||||
@@ -649,7 +747,17 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
//排序 从大到小
|
//排序 从大到小
|
||||||
const sortDesignCollection = ()=> {
|
const sortDesignCollection = ()=> {
|
||||||
|
if(editPrintElementData.stateOverallSingle == 'overall'){
|
||||||
|
let arr:any = editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle]
|
||||||
|
let tokenList = arr.map((item)=>({token:item.token,srot:item.pattern.style.zIndex}))
|
||||||
|
let tokens = tokenList.sort((a:any,b:any)=>a.srot - b.srot).map((item:any)=>item.token)
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.SORT,
|
||||||
|
tokens: tokens,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const reRange = (item:any, x:number, y:number,str?:string)=>{
|
const reRange = (item:any, x:number, y:number,str?:string)=>{
|
||||||
let elList:any = collItemSize.elList
|
let elList:any = collItemSize.elList
|
||||||
@@ -692,6 +800,14 @@ export default defineComponent({
|
|||||||
const navDelete = (item:any)=>{
|
const navDelete = (item:any)=>{
|
||||||
let arr:any = editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle]
|
let arr:any = editPrintElementData.printStyleList[props.type][editPrintElementData.stateOverallSingle]
|
||||||
let index = arr.findIndex((arrItem:any)=>arrItem.uniqueId == item.uniqueId)
|
let index = arr.findIndex((arrItem:any)=>arrItem.uniqueId == item.uniqueId)
|
||||||
|
if(editPrintElementData.stateOverallSingle == 'overall'){
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.DELETE,
|
||||||
|
token: arr[index].token,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
arr.splice(index,1)
|
arr.splice(index,1)
|
||||||
setItemPosition()
|
setItemPosition()
|
||||||
}
|
}
|
||||||
@@ -738,6 +854,106 @@ export default defineComponent({
|
|||||||
collItemSize.prentWidth = (collItemSize.padding + remValue) * elArr.length + 'px'
|
collItemSize.prentWidth = (collItemSize.padding + remValue) * elArr.length + 'px'
|
||||||
moveItem()
|
moveItem()
|
||||||
}
|
}
|
||||||
|
const updateCanvas = (arr)=>{//画布操作更新对应的参数
|
||||||
|
let list = editPrintElementData.printStyleList[props.type].overall
|
||||||
|
arr.forEach((item)=>{
|
||||||
|
const obj = list.find((v) => v.token === item.token);
|
||||||
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
|
if (item.action === ACTIONS.UPDATE) {
|
||||||
|
try {
|
||||||
|
const key = item.key;
|
||||||
|
const str = /^\[/.test(item.key)
|
||||||
|
? "obj" + key
|
||||||
|
: "obj." + key;
|
||||||
|
eval(`${str} = item.value`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item.action === ACTIONS.SELECT) {
|
||||||
|
overallSetIndex(obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const inputFillAngle = (angle:any)=>{
|
||||||
|
let arr = editPrintElementData.printStyleList[props.type].overall
|
||||||
|
arr[editPrintElementData.imgDomIndex].angle = angle
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.UPDATE,
|
||||||
|
token: arr[editPrintElementData.imgDomIndex].token,
|
||||||
|
key: 'angle',
|
||||||
|
value: angle,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
const inputFillOffset = (offset:any)=>{
|
||||||
|
let arr = editPrintElementData.printStyleList[props.type].overall
|
||||||
|
arr[editPrintElementData.imgDomIndex].location = [offset.left * offset.size[0] / 100,offset.top * offset.size[1] / 100]
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.UPDATE,
|
||||||
|
token: arr[editPrintElementData.imgDomIndex].token,
|
||||||
|
key: 'location[0]',
|
||||||
|
value: offset.left,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.UPDATE,
|
||||||
|
token: arr[editPrintElementData.imgDomIndex].token,
|
||||||
|
key: 'location[1]',
|
||||||
|
value: offset.top,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
// editPrintElementData.overallDetail.offsetX = offset.left
|
||||||
|
// editPrintElementData.overallDetail.offsetY = offset.top
|
||||||
|
}
|
||||||
|
const inputFillScale = (scale:any)=>{
|
||||||
|
let arr = editPrintElementData.printStyleList[props.type].overall
|
||||||
|
arr[editPrintElementData.imgDomIndex].scale = [scale,scale]
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.UPDATE,
|
||||||
|
token: arr[editPrintElementData.imgDomIndex].token,
|
||||||
|
key: 'scale[0]',
|
||||||
|
value: scale,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
const inputFill_Gap = (x:any,y:any)=>{
|
||||||
|
let arr = editPrintElementData.printStyleList[props.type].overall
|
||||||
|
arr[editPrintElementData.imgDomIndex].object.gapX = x
|
||||||
|
arr[editPrintElementData.imgDomIndex].object.gapY = y
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.UPDATE,
|
||||||
|
token: arr[editPrintElementData.imgDomIndex].token,
|
||||||
|
key: "object.gapX",
|
||||||
|
value: x,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.UPDATE,
|
||||||
|
token: arr[editPrintElementData.imgDomIndex].token,
|
||||||
|
key: "object.gapY",
|
||||||
|
value: y,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
const overallSetIndex = (item)=>{
|
||||||
|
if(editPrintElementData.stateOverallSingle !== 'overall')return
|
||||||
|
let arr = editPrintElementData.printStyleList[props.type].overall
|
||||||
|
let index = arr.findIndex((arrItem:any)=>arrItem.token == item.token)
|
||||||
|
editPrintElementData.imgDomIndex = index
|
||||||
|
editPrintElementDom.pingpuRef.updataList([
|
||||||
|
{
|
||||||
|
action: ACTIONS.SELECT,
|
||||||
|
token: arr[index].token,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
if(props.type == 'element'){
|
if(props.type == 'element'){
|
||||||
editPrintElementData.stateOverallSingle = 'single'
|
editPrintElementData.stateOverallSingle = 'single'
|
||||||
@@ -747,6 +963,7 @@ export default defineComponent({
|
|||||||
previewDetailPrintData()
|
previewDetailPrintData()
|
||||||
})
|
})
|
||||||
return{
|
return{
|
||||||
|
t,
|
||||||
getMousePosition,
|
getMousePosition,
|
||||||
...toRefs(editPrintElementDom),
|
...toRefs(editPrintElementDom),
|
||||||
...toRefs(editPrintElementData),
|
...toRefs(editPrintElementData),
|
||||||
@@ -760,6 +977,12 @@ export default defineComponent({
|
|||||||
clearOverall,
|
clearOverall,
|
||||||
designMousedown,
|
designMousedown,
|
||||||
navDelete,
|
navDelete,
|
||||||
|
updateCanvas,
|
||||||
|
inputFillAngle,
|
||||||
|
inputFillOffset,
|
||||||
|
inputFillScale,
|
||||||
|
inputFill_Gap,
|
||||||
|
overallSetIndex,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives:{
|
directives:{
|
||||||
@@ -876,7 +1099,10 @@ export default defineComponent({
|
|||||||
.habit_System_Designer {
|
.habit_System_Designer {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: flex-end;
|
||||||
|
margin-top: 1.8rem;
|
||||||
|
margin-right: .8rem;
|
||||||
|
|
||||||
.ant-slider-track,
|
.ant-slider-track,
|
||||||
.ant-slider-rail {
|
.ant-slider-rail {
|
||||||
background-color: #e1e1e1;
|
background-color: #e1e1e1;
|
||||||
@@ -924,6 +1150,9 @@ export default defineComponent({
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 1rem;
|
border-radius: 1rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
&.active{
|
||||||
|
border: 2px solid #B4B4B4;
|
||||||
|
}
|
||||||
> img{
|
> img{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -977,13 +1206,23 @@ export default defineComponent({
|
|||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
// max-height: 80%;
|
// max-height: 80%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
>img{
|
>img{
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
position: relative;
|
position: relative;
|
||||||
// height: 100%;
|
// height: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
// width: 100%;
|
// width: 100%;
|
||||||
|
&.designOpenrtion_sketchMask{
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.designOpenrtion_sketch_mask{
|
.designOpenrtion_sketch_mask{
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@@ -1013,8 +1252,13 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.designOpenrtion_pingpu{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
.designOpenrtion_btn{
|
.designOpenrtion_btn{
|
||||||
z-index: 3;
|
z-index: 99;
|
||||||
>div{
|
>div{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
</div> -->
|
</div> -->
|
||||||
<sketchType v-if="currentDetailType === 'sketch'"></sketchType>
|
<sketchType v-if="currentDetailType === 'sketch'"></sketchType>
|
||||||
<!-- <printType v-if="currentDetailType === 'print'"></printType> -->
|
<!-- <printType v-if="currentDetailType === 'print'"></printType> -->
|
||||||
<editPrintElement ref="editPrintElement" v-if="currentDetailType === 'print'" type="print"></editPrintElement>
|
<editPrintElement ref="editPrintElement" v-if="currentDetailType === 'print'" type="print" :sketchSize="sketchSize"></editPrintElement>
|
||||||
<editPrintElement ref="editPrintElement" v-if="currentDetailType === 'element'" type="element"></editPrintElement>
|
<editPrintElement ref="editPrintElement" v-if="currentDetailType === 'element'" type="element" :sketchSize="sketchSize"></editPrintElement>
|
||||||
<modelsType ref="modelsType" v-if="currentDetailType === 'models'"></modelsType>
|
<modelsType ref="modelsType" v-if="currentDetailType === 'models'"></modelsType>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -24,6 +24,12 @@ export default defineComponent({
|
|||||||
components:{
|
components:{
|
||||||
sketchType,printType,editPrintElement,modelsType
|
sketchType,printType,editPrintElement,modelsType
|
||||||
},
|
},
|
||||||
|
props:{
|
||||||
|
sketchSize:{
|
||||||
|
type:Object,
|
||||||
|
default:()=>{}
|
||||||
|
},
|
||||||
|
},
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const detailData = reactive({
|
const detailData = reactive({
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<div class="repeat-setting">
|
||||||
|
{{ }}
|
||||||
|
<div class="repeat-setting-item">
|
||||||
|
<span class="label">{{ t("Canvas.angle") }}</span>
|
||||||
|
<angle-tool
|
||||||
|
:angle="angle"
|
||||||
|
styleType="2"
|
||||||
|
@input="(e) => emit('inputFillAngle', e)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<div class="repeat-setting-item">
|
||||||
|
<span class="label">{{ t("Canvas.scale") }}</span>
|
||||||
|
<slider
|
||||||
|
:min="1"
|
||||||
|
:max="1000"
|
||||||
|
:step="1"
|
||||||
|
is-input
|
||||||
|
:tipFormatter="(v) => `${scale}%`"
|
||||||
|
:value="scale"
|
||||||
|
@input="inputFillScale"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<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"
|
||||||
|
@input="(e) => emit('inputFill_Gap', e, gapY)"
|
||||||
|
@change="(e) => emit('changeFill_Gap', e, gapY)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<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"
|
||||||
|
@input="(e) => emit('inputFill_Gap', gapX, e)"
|
||||||
|
@change="(e) => emit('changeFill_Gap', gapX, e)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
<div class="repeat-setting-item">
|
||||||
|
<span class="label">{{ t("Canvas.offset") }}</span>
|
||||||
|
<offset-tool
|
||||||
|
:top="offset[1]"
|
||||||
|
:left="offset[0]"
|
||||||
|
@input="inputOffset"
|
||||||
|
@change="(e) => emit('changeFillOffset', e)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, computed } from "vue";
|
||||||
|
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();
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
object: {
|
||||||
|
required: true,
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
sketchPath: {
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const angle = computed(() => props.object?.angle || 0);
|
||||||
|
const scale = computed(() => {
|
||||||
|
// let scaleValue = props.object?.scale/10;
|
||||||
|
// return props.object?.scale/10;
|
||||||
|
return props.object?.scale[0] * 100;
|
||||||
|
});
|
||||||
|
const offset = ref([0,0])
|
||||||
|
const sketchSize:any = async ()=>{
|
||||||
|
let img = new Image();
|
||||||
|
let size = [0,0];
|
||||||
|
img.src = props.sketchPath;
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
img.onload = () => {
|
||||||
|
size = [img.width, img.height]
|
||||||
|
resolve([img.width, img.height]);
|
||||||
|
}
|
||||||
|
img.onerror = reject;
|
||||||
|
});
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
watch (() => props.object.path || props.object.location, async () => {
|
||||||
|
let size = await sketchSize();
|
||||||
|
offset.value[0] = props.object.location[0] / size[0] * 100;
|
||||||
|
offset.value[1] = props.object.location[1] / size[1] * 100;
|
||||||
|
},{immediate: true})
|
||||||
|
const gapX = computed(() => props.object.object?.gapX || 0);
|
||||||
|
const gapY = computed(() => props.object.object?.gapY || 0);
|
||||||
|
const emit = defineEmits([
|
||||||
|
"inputFillAngle",
|
||||||
|
"changeFillAngle",
|
||||||
|
"inputFillOffset",
|
||||||
|
"changeFillOffset",
|
||||||
|
"inputFillScale",
|
||||||
|
"changeFillScale",
|
||||||
|
"inputFill_Gap",
|
||||||
|
"changeFill_Gap",
|
||||||
|
]);
|
||||||
|
const inputFillScale = (e) => {
|
||||||
|
const scale = e / 100;
|
||||||
|
console.log(scale)
|
||||||
|
emit("inputFillScale", scale);
|
||||||
|
};
|
||||||
|
const inputOffset = async (e:any)=>{
|
||||||
|
emit('inputFillOffset', {...e,size: await sketchSize()})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.repeat-setting {
|
||||||
|
user-select: none;
|
||||||
|
width: 228px;
|
||||||
|
> .title {
|
||||||
|
line-height: 35px;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: -12px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
> .repeat-setting-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
&.offset {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
> .label {
|
||||||
|
min-width: 68px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
&:not(.offset) > div {
|
||||||
|
width: 120px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
> .slider {
|
||||||
|
--slider-thumb-color1: #000;
|
||||||
|
--slider-thumb-color2: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
<template>
|
||||||
|
<div class="angle-tool" :disabled="disabled">
|
||||||
|
<template v-if="styleType === '1'">
|
||||||
|
<div
|
||||||
|
ref="dishRef"
|
||||||
|
class="dish"
|
||||||
|
@mousedown.stop="mousedown"
|
||||||
|
@touchmove.stop="mousedown"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="pointer"
|
||||||
|
:style="{ transform: `rotate(${angle}deg)` }"
|
||||||
|
>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="input">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="angle"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<my-input
|
||||||
|
v-if="styleType === '2'"
|
||||||
|
v-model="angle"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
type="number"
|
||||||
|
after="°"
|
||||||
|
icon="icon-angle"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
import { calculateAngle } from "@/component/Canvas/CanvasEditor/utils/helper";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
|
// Props
|
||||||
|
const props = defineProps({
|
||||||
|
styleType: {
|
||||||
|
type: String,
|
||||||
|
default: "1",
|
||||||
|
},
|
||||||
|
angle: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["change", "input"]);
|
||||||
|
const angle = ref(props.angle);
|
||||||
|
watch(
|
||||||
|
() => props.angle,
|
||||||
|
(value) => {
|
||||||
|
angle.value = value;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const dishRef = ref<HTMLDivElement>();
|
||||||
|
const mousedown = (e: MouseEvent | TouchEvent) => {
|
||||||
|
if (props.disabled) return;
|
||||||
|
const mousemove = (e: MouseEvent | TouchEvent) => {
|
||||||
|
if (!dishRef.value) return;
|
||||||
|
const { left, top, width, height } =
|
||||||
|
dishRef.value.getBoundingClientRect();
|
||||||
|
const centerX = left + width / 2;
|
||||||
|
const centerY = top + height / 2;
|
||||||
|
const { clientX, clientY } = e?.touches?.[0] || e;
|
||||||
|
angle.value = calculateAngle(centerX, centerY, clientX, clientY, true);
|
||||||
|
onInput();
|
||||||
|
};
|
||||||
|
mousemove(e);
|
||||||
|
const mouseup = () => {
|
||||||
|
onChange();
|
||||||
|
document.removeEventListener("mousemove", mousemove);
|
||||||
|
document.removeEventListener("touchmove", mousemove);
|
||||||
|
document.removeEventListener("mouseup", mouseup);
|
||||||
|
document.removeEventListener("touchend", mouseup);
|
||||||
|
};
|
||||||
|
document.addEventListener("mousemove", mousemove);
|
||||||
|
document.addEventListener("touchmove", mousemove);
|
||||||
|
document.addEventListener("mouseup", mouseup);
|
||||||
|
document.addEventListener("touchend", mouseup);
|
||||||
|
};
|
||||||
|
const onInput = () => !props.disabled && emit("input", angle.value);
|
||||||
|
var changeTime: any = null;
|
||||||
|
const onChange = () => {
|
||||||
|
if (props.disabled) return;
|
||||||
|
clearTimeout(changeTime);
|
||||||
|
changeTime = setTimeout(() => emit("change", angle.value), 500);
|
||||||
|
};
|
||||||
|
// var angleTime = null;
|
||||||
|
// watch(angle, (value) => {
|
||||||
|
// emit("input", value);
|
||||||
|
// clearTimeout(angleTime);
|
||||||
|
// angleTime = setTimeout(() => emit("change", value), 50);
|
||||||
|
// });
|
||||||
|
// defineExpose({
|
||||||
|
// open,
|
||||||
|
// close,
|
||||||
|
// });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.angle-tool {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
--color: #000;
|
||||||
|
&[disabled="true"] {
|
||||||
|
--color: #b2b2b2;
|
||||||
|
> .dish {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .dish {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
border: 1px solid var(--color);
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
> .pointer {
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
> span {
|
||||||
|
position: absolute;
|
||||||
|
top: 10%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
width: 35%;
|
||||||
|
height: 35%;
|
||||||
|
background-color: var(--color);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .input {
|
||||||
|
margin-left: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color);
|
||||||
|
flex: 1;
|
||||||
|
// min-width: 45px;
|
||||||
|
// max-width: 80px;
|
||||||
|
// width: 50px;
|
||||||
|
> input {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .my-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="my-input">
|
||||||
|
<span class="decorate"></span>
|
||||||
|
<span v-show="icon" :class="['iconfont', icon]"></span>
|
||||||
|
<span v-show="before" class="before">{{ before }}</span>
|
||||||
|
<input v-bind="$attrs" :value="modelValue" @input="onInput" />
|
||||||
|
<span v-show="after" class="after">{{ after }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: { type: Number, default: 0 },
|
||||||
|
icon: { default: "", type: String },
|
||||||
|
before: { default: "", type: String },
|
||||||
|
after: { default: "", type: String },
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["update:modelValue", "input"]);
|
||||||
|
const onInput = (e) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
emit("update:modelValue", value);
|
||||||
|
emit("input", value);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.my-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid rgba(230, 230, 231, 1);
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0 4px 0 2px;
|
||||||
|
> .decorate {
|
||||||
|
width: 2px;
|
||||||
|
background-color: rgba(230, 230, 231, 1);
|
||||||
|
border-radius: 3px;
|
||||||
|
height: 85%;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
> .iconfont {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #000;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
> .before {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #000;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
> .after {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
> input {
|
||||||
|
font-size: 12px;
|
||||||
|
width: 0;
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<a-select
|
||||||
|
class="my-select"
|
||||||
|
:size="size"
|
||||||
|
@change="change"
|
||||||
|
:defaultValue="defaultValue"
|
||||||
|
@dropdownVisibleChange="dropdownVisibleChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<a-select-option
|
||||||
|
v-for="v in list"
|
||||||
|
:key="v.value"
|
||||||
|
:value="v.value"
|
||||||
|
:title="v.tip"
|
||||||
|
@mouseover.stop.prevent="mouseover(v)"
|
||||||
|
@mouseleave="mouseleave(v)"
|
||||||
|
>{{ v.label }}</a-select-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
const props = defineProps({
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
defaultValue: {
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: "small",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["change", "active"]);
|
||||||
|
const isChange = ref(false);
|
||||||
|
const initValue = ref(props.defaultValue);
|
||||||
|
const activeValue = ref(props.defaultValue);
|
||||||
|
const timeout = ref(null);
|
||||||
|
const mouseover = (v) => {
|
||||||
|
clearTimeout(timeout.value);
|
||||||
|
if (v.value === activeValue.value) return;
|
||||||
|
emit("active", v.value, activeValue.value);
|
||||||
|
activeValue.value = v.value;
|
||||||
|
};
|
||||||
|
const mouseleave = () => {
|
||||||
|
clearTimeout(timeout.value);
|
||||||
|
timeout.value = setTimeout(() => {
|
||||||
|
dropdownVisibleChange(false);
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
const change = (v) => {
|
||||||
|
isChange.value = true;
|
||||||
|
emit("change", v, initValue.value);
|
||||||
|
};
|
||||||
|
const dropdownVisibleChange = (v) => {
|
||||||
|
if (v) {
|
||||||
|
isChange.value = false;
|
||||||
|
initValue.value = props.defaultValue;
|
||||||
|
} else if (!isChange.value) {
|
||||||
|
emit("active", initValue.value, activeValue.value);
|
||||||
|
activeValue.value = initValue.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
<template>
|
||||||
|
<div class="offset-tool">
|
||||||
|
<div class="input" v-show="showInput">
|
||||||
|
<my-input
|
||||||
|
v-model="left"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
type="number"
|
||||||
|
before="X"
|
||||||
|
after="%"
|
||||||
|
:min="-100"
|
||||||
|
:max="100"
|
||||||
|
/>
|
||||||
|
<my-input
|
||||||
|
v-model="top"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
type="number"
|
||||||
|
before="Y"
|
||||||
|
after="%"
|
||||||
|
:min="-100"
|
||||||
|
:max="100"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="dish"
|
||||||
|
@mousedown="mousedown"
|
||||||
|
@touchstart="mousedown"
|
||||||
|
ref="dishRef"
|
||||||
|
v-show="showDish"
|
||||||
|
>
|
||||||
|
<img src="/src/assets/images/icon/xyz.png" />
|
||||||
|
<span class="ball" :style="ballStyle"></span>
|
||||||
|
<span class="tip x">X: {{ left }}%</span>
|
||||||
|
<span class="tip y">Y: {{ top }}%</span>
|
||||||
|
<span class="line x"></span>
|
||||||
|
<span class="line y"></span>
|
||||||
|
<span class="line z" :style="lineZStyle"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch, computed } from "vue";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
|
const props = defineProps({
|
||||||
|
left: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
showInput: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
showDish: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["change", "input"]);
|
||||||
|
// 工具的实际坐标 -100 ~ 100
|
||||||
|
const top = ref(Math.round(props.top));
|
||||||
|
const left = ref(Math.round(props.left));
|
||||||
|
|
||||||
|
// 原点的坐标 0 ~ 100
|
||||||
|
const ballStyle = computed(() => ({
|
||||||
|
top: 50 + Number(top.value) / 2 + "%",
|
||||||
|
left: 50 + Number(left.value) / 2 + "%",
|
||||||
|
}));
|
||||||
|
watch(
|
||||||
|
() => props.left,
|
||||||
|
(v) => (left.value = Math.round(v))
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.top,
|
||||||
|
(v) => (top.value = Math.round(v))
|
||||||
|
);
|
||||||
|
const dishRef = ref<HTMLDivElement>();
|
||||||
|
const mousedown = (e: MouseEvent | TouchEvent) => {
|
||||||
|
if (!dishRef.value) return;
|
||||||
|
const mousemove = (e: MouseEvent | TouchEvent) => {
|
||||||
|
if (!dishRef.value) return;
|
||||||
|
const rect = dishRef.value.getBoundingClientRect();
|
||||||
|
const X = e.clientX || (e as TouchEvent).touches[0].clientX;
|
||||||
|
const Y = e.clientY || (e as TouchEvent).touches[0].clientY;
|
||||||
|
var x = ((X - rect.left) / rect.width) * 100;
|
||||||
|
var y = ((Y - rect.top) / rect.height) * 100;
|
||||||
|
if (x < 0) x = 0;
|
||||||
|
if (x > 100) x = 100;
|
||||||
|
if (y < 0) y = 0;
|
||||||
|
if (y > 100) y = 100;
|
||||||
|
left.value = Math.round((x - 50) * 2);
|
||||||
|
top.value = Math.round((y - 50) * 2);
|
||||||
|
onInput();
|
||||||
|
};
|
||||||
|
mousemove(e);
|
||||||
|
const mouseup = () => {
|
||||||
|
onChange();
|
||||||
|
document.removeEventListener("mousemove", mousemove);
|
||||||
|
document.removeEventListener("touchmove", mousemove);
|
||||||
|
document.removeEventListener("mouseup", mouseup);
|
||||||
|
document.removeEventListener("touchend", mouseup);
|
||||||
|
};
|
||||||
|
document.addEventListener("mousemove", mousemove);
|
||||||
|
document.addEventListener("touchmove", mousemove);
|
||||||
|
document.addEventListener("mouseup", mouseup);
|
||||||
|
document.addEventListener("touchend", mouseup);
|
||||||
|
};
|
||||||
|
const onInput = () => {
|
||||||
|
emit("input", { left: left.value, top: top.value });
|
||||||
|
};
|
||||||
|
var changeTime: any = null;
|
||||||
|
const onChange = () => {
|
||||||
|
clearTimeout(changeTime);
|
||||||
|
changeTime = setTimeout(() => {
|
||||||
|
emit("change", {
|
||||||
|
left: left.value,
|
||||||
|
top: top.value,
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
const lineZStyle = computed(() => ({
|
||||||
|
"--rotateZ": calculateAngle(0, 0, left.value, top.value) + "deg",
|
||||||
|
width: calculateDistance(0, 0, left.value, top.value) / 2 + "%",
|
||||||
|
}));
|
||||||
|
// 计算角度
|
||||||
|
function calculateAngle(x1: number, y1: number, x2: number, y2: number) {
|
||||||
|
const deltaX = x2 - x1;
|
||||||
|
const deltaY = y1 - y2;
|
||||||
|
let angle = Math.atan2(deltaX, deltaY) * (180 / Math.PI) - 90;
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
// 计算距离
|
||||||
|
function calculateDistance(x1: number, y1: number, x2: number, y2: number) {
|
||||||
|
const deltaX = x2 - x1;
|
||||||
|
const deltaY = y2 - y1;
|
||||||
|
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.offset-tool {
|
||||||
|
position: relative;
|
||||||
|
> .input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 12px;
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .dish {
|
||||||
|
width: 135px;
|
||||||
|
height: 135px;
|
||||||
|
border: 1px solid #eaeaea;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
margin-top: 24px;
|
||||||
|
> * {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
> img {
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
bottom: 4px;
|
||||||
|
right: 4px;
|
||||||
|
}
|
||||||
|
> .ball {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
background-color: #333;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 0.68px 1.7px 0px rgba(0, 0, 0, 0.26);
|
||||||
|
}
|
||||||
|
> .tip {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #000;
|
||||||
|
line-height: 24px;
|
||||||
|
&.x {
|
||||||
|
top: 50%;
|
||||||
|
right: 0%;
|
||||||
|
transform: translate(100%, -50%);
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
&.y {
|
||||||
|
top: 0%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .line {
|
||||||
|
border-color: #d9d9d9;
|
||||||
|
border-style: dashed;
|
||||||
|
border-width: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
&.x {
|
||||||
|
width: 100%;
|
||||||
|
border-top-width: 1px;
|
||||||
|
}
|
||||||
|
&.y {
|
||||||
|
height: 100%;
|
||||||
|
border-left-width: 1px;
|
||||||
|
}
|
||||||
|
&.z {
|
||||||
|
width: 50%;
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-color: #454754;
|
||||||
|
transform: translate(0%, -50%) rotateZ(var(--rotateZ));
|
||||||
|
transform-origin: left center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
173
src/component/Detail/detailRight/overallSetting/tools/Slider.vue
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<template>
|
||||||
|
<div class="slider" :disabled="disabled">
|
||||||
|
<div
|
||||||
|
class="input-range"
|
||||||
|
:style="{
|
||||||
|
'--progress': (value - props.min) / (props.max - props.min),
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span class="tip">{{ props.tipFormatter(value) }}</span>
|
||||||
|
<input
|
||||||
|
type="range"
|
||||||
|
v-model="value"
|
||||||
|
:min="props.min"
|
||||||
|
:max="props.max"
|
||||||
|
:step="props.step"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="input" v-show="isInput">
|
||||||
|
<my-input
|
||||||
|
v-model="value"
|
||||||
|
:min="props.min"
|
||||||
|
:max="props.max"
|
||||||
|
:step="props.step"
|
||||||
|
@input="onInput"
|
||||||
|
@change="onChange"
|
||||||
|
:disabled="disabled"
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||||
|
import MyInput from "./MyInput.vue";
|
||||||
|
const props = defineProps({
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
max: {
|
||||||
|
type: Number,
|
||||||
|
default: 100,
|
||||||
|
},
|
||||||
|
step: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
tipFormatter: {
|
||||||
|
type: Function,
|
||||||
|
default: (v) => v,
|
||||||
|
},
|
||||||
|
isInput: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["change", "input"]);
|
||||||
|
const value = ref(props.value);
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(v) => (value.value = v)
|
||||||
|
);
|
||||||
|
const onInput = () => !props.disabled && emit("input", Number(value.value));
|
||||||
|
var changeTime: any = null;
|
||||||
|
const onChange = () => {
|
||||||
|
if (props.disabled) return;
|
||||||
|
clearTimeout(changeTime);
|
||||||
|
changeTime = setTimeout(() => emit("change", Number(value.value)), 500);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.slider {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 150px;
|
||||||
|
--input-thumb-size: 10px;
|
||||||
|
--backcolor1: var(--slider-thumb-color1, #4285f4);
|
||||||
|
--backcolor2: var(--slider-thumb-color2, rgba(0, 0, 0, 0.1));
|
||||||
|
&:hover {
|
||||||
|
> .input-range > .tip {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .input-range {
|
||||||
|
position: relative;
|
||||||
|
flex: 2;
|
||||||
|
> input {
|
||||||
|
width: 100%;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
height: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
outline: none;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
var(--backcolor1) 0%,
|
||||||
|
var(--backcolor1) calc(var(--progress) * 100%),
|
||||||
|
var(--backcolor2) calc(var(--progress) * 100%),
|
||||||
|
var(--backcolor2) 100%
|
||||||
|
);
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: var(--input-thumb-size);
|
||||||
|
height: var(--input-thumb-size);
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--backcolor1); /* 蓝色滑块 */
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
&::-webkit-slider-thumb:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .tip {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 10px;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
color: #666;
|
||||||
|
top: 0;
|
||||||
|
left: calc(
|
||||||
|
(100% - var(--input-thumb-size)) * var(--progress) +
|
||||||
|
var(--input-thumb-size) / 2
|
||||||
|
);
|
||||||
|
transform: translate(-50%, -100%);
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
color: white;
|
||||||
|
padding: 0.4rem 0.8rem;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
pointer-events: none;
|
||||||
|
display: none;
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 97%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
border-top: 5px solid rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .input {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 10px;
|
||||||
|
> input {
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
<div class="back" v-show="isEditPattern.value">
|
<div class="back" v-show="isEditPattern.value">
|
||||||
<i class="fi fi-br-angle-left" @click="setBack"></i>
|
<i class="fi fi-br-angle-left" @click="setBack"></i>
|
||||||
</div>
|
</div>
|
||||||
<modelNav @canvasReload="()=>$emit('canvasReload')" @addSketch="()=>$emit('addSketch')" @sketchSysToLibrary="()=>$emit('sketchSysToLibrary')" @deleteItem="deleteItem"></modelNav>
|
<modelNav ref="modelNav" @addSketch="()=>$emit('addSketch')" @sketchSysToLibrary="()=>$emit('sketchSysToLibrary')" @deleteItem="deleteItem"></modelNav>
|
||||||
</div>
|
</div>
|
||||||
<div class="modelindex_right">
|
<div class="modelindex_right" ref="modelindexRight">
|
||||||
<div class="detail_btn">
|
<div class="detail_btn">
|
||||||
<!-- 全屏 -->
|
<!-- 全屏 -->
|
||||||
<!-- <i class="fi fi-bs-expand-arrows-alt" @click="showDesignImgDetail('2')"></i> -->
|
<!-- <i class="fi fi-bs-expand-arrows-alt" @click="showDesignImgDetail('2')"></i> -->
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<i class="icon iconfont icon-chehui" @click="revocation"></i>
|
<i class="icon iconfont icon-chehui" @click="revocation"></i>
|
||||||
<i class="icon iconfont icon-fanchehui" @click="oppositeRevocation"></i>
|
<i class="icon iconfont icon-fanchehui" @click="oppositeRevocation"></i>
|
||||||
<!-- 编辑 -->
|
<!-- 编辑 -->
|
||||||
<i class="fi fi-rs-pencil-paintbrush" :title="$t('DesignDetail.editSketchTitle')" :class="{'pointerEventsNone':!selectDetail?.id}" @click="()=>$emit('addDetail')"></i>
|
<i class="fi fi-rs-pencil-paintbrush" :title="$t('DesignDetail.editSketchTitle')" :class="{'pointerEventsNone':!selectDetail?.id,active:isEditPattern.value == 'editSketch'}" @click="showDesignImgDetail('editSketch')"></i>
|
||||||
<i class="fi fi-rr-edit" :title="$t('DesignDetail.editTitle')" :class="{active:isEditPattern.value == 'canvasEditor','pointerEventsNone':!selectDetail?.id}" @click="showDesignImgDetail('canvasEditor')"></i>
|
<i class="fi fi-rr-edit" :title="$t('DesignDetail.editTitle')" :class="{active:isEditPattern.value == 'canvasEditor','pointerEventsNone':!selectDetail?.id}" @click="showDesignImgDetail('canvasEditor')"></i>
|
||||||
|
|
||||||
<i class="icon iconfont icon-clothes" :title="$t('Canvas.editFrontBack')" style="font-size: 3.2rem;" @click="showDesignImgDetail('redGreenExample')" :class="{active:isEditPattern.value == 'redGreenExample','pointerEventsNone':!selectDetail?.id}"></i>
|
<i class="icon iconfont icon-clothes" :title="$t('Canvas.editFrontBack')" style="font-size: 3.2rem;" @click="showDesignImgDetail('redGreenExample')" :class="{active:isEditPattern.value == 'redGreenExample','pointerEventsNone':!selectDetail?.id}"></i>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</i>
|
</i>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<position ref="position" @modelOnLoad="()=>$emit('modelOnLoad')" @canvasReload="()=>$emit('canvasReload')" @addSketch="()=>$emit('addSketch')" :imgDesignImg=imgDesignImg></position>
|
<position ref="position" @addSketch="()=>$emit('addSketch')" :imgDesignImg=imgDesignImg></position>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -51,7 +51,7 @@ export default defineComponent({
|
|||||||
components:{
|
components:{
|
||||||
position,modelNav
|
position,modelNav
|
||||||
},
|
},
|
||||||
emits:['detailEdit','canvasReload','addSketch','revocation','oppositeRevocation','modelOnLoad','sketchSysToLibrary','addDetail'],
|
emits:['detailEdit','addSketch','revocation','oppositeRevocation','sketchSysToLibrary'],
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -68,36 +68,40 @@ export default defineComponent({
|
|||||||
const getDetailListDom = reactive({
|
const getDetailListDom = reactive({
|
||||||
libraryList:null as any,
|
libraryList:null as any,
|
||||||
position:null as any,
|
position:null as any,
|
||||||
|
modelindexRight:null as any,
|
||||||
|
modelNav:null as any,
|
||||||
})
|
})
|
||||||
const getSubmitData = (value:any,boolean)=>{
|
const getSubmitData = (value:any)=>{
|
||||||
return getDetailListDom.position.getSubmitData(value,boolean)
|
return getDetailListDom.position.getSubmitData(value,)
|
||||||
}
|
}
|
||||||
const showDesignImgDetail = (str:any)=>{
|
const showDesignImgDetail = (str:any)=>{
|
||||||
new Promise((resolve, reject) => {
|
emit('detailEdit',str)
|
||||||
if(
|
|
||||||
getDetailListData.isEditPattern.value&&
|
// new Promise((resolve, reject) => {
|
||||||
detailData?.getCanvasIfEdit?.fun&&detailData?.getCanvasIfEdit?.fun() > 0
|
// if(
|
||||||
){
|
// getDetailListData.isEditPattern.value&&
|
||||||
Modal.confirm({
|
// detailData?.getCanvasIfEdit?.fun&&detailData?.getCanvasIfEdit?.fun() > 0
|
||||||
title: t('collectionModal.jsContent2'),
|
// ){
|
||||||
icon: createVNode(ExclamationCircleOutlined),
|
// Modal.confirm({
|
||||||
okText: 'Yes',
|
// title: t('collectionModal.jsContent2'),
|
||||||
cancelText: 'No',
|
// icon: createVNode(ExclamationCircleOutlined),
|
||||||
mask:false,
|
// okText: 'Yes',
|
||||||
centered:true,
|
// cancelText: 'No',
|
||||||
onOk() {
|
// mask:false,
|
||||||
resolve(true)
|
// centered:true,
|
||||||
emit('detailEdit',str)
|
// onOk() {
|
||||||
},
|
// resolve(true)
|
||||||
onCancel(){
|
// emit('detailEdit',str)
|
||||||
resolve(false)
|
// },
|
||||||
}
|
// onCancel(){
|
||||||
});
|
// resolve(false)
|
||||||
}else{
|
// }
|
||||||
resolve(true)
|
// });
|
||||||
emit('detailEdit',str)
|
// }else{
|
||||||
}
|
// resolve(true)
|
||||||
})
|
// emit('detailEdit',str)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
}
|
}
|
||||||
const deleteItem = ()=>{
|
const deleteItem = ()=>{
|
||||||
setRevocation()
|
setRevocation()
|
||||||
@@ -121,18 +125,25 @@ export default defineComponent({
|
|||||||
clearTimeout(time)
|
clearTimeout(time)
|
||||||
time = setTimeout(()=>{
|
time = setTimeout(()=>{
|
||||||
store.commit('DesignDetail/setDesignDetail',getDetailListData.designDetail)
|
store.commit('DesignDetail/setDesignDetail',getDetailListData.designDetail)
|
||||||
getDetailListDom.position.updataPosition()
|
getDetailListDom.position?.updataPosition?.()
|
||||||
|
getDetailListDom.modelNav?.setItemPosition?.()
|
||||||
},1000)
|
getDetailListDom.position?.updateRect?.()
|
||||||
|
},500)
|
||||||
}
|
}
|
||||||
const setBack = ()=>{
|
const setBack = ()=>{
|
||||||
emit('detailEdit')
|
showDesignImgDetail(getDetailListData.isEditPattern.value)
|
||||||
}
|
}
|
||||||
|
let observers = null as any
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
window.addEventListener('resize', handleResize);
|
observers = new ResizeObserver(entries => {
|
||||||
|
for (let entry of entries) {
|
||||||
|
handleResize()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
observers.observe(getDetailListDom.modelindexRight);
|
||||||
})
|
})
|
||||||
onBeforeUnmount(()=>{
|
onBeforeUnmount(()=>{
|
||||||
window.removeEventListener('resize', handleResize);
|
observers.disconnect();
|
||||||
})
|
})
|
||||||
return{
|
return{
|
||||||
...toRefs(detailData),
|
...toRefs(detailData),
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export default defineComponent({
|
|||||||
components:{
|
components:{
|
||||||
position,
|
position,
|
||||||
},
|
},
|
||||||
emits:['canvasReload','addSketch','deleteItem','sketchSysToLibrary'],
|
emits:['addSketch','deleteItem','sketchSysToLibrary'],
|
||||||
props:{
|
props:{
|
||||||
},
|
},
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
@@ -79,25 +79,25 @@ export default defineComponent({
|
|||||||
detailData.selectDetail?.id &&
|
detailData.selectDetail?.id &&
|
||||||
detailData?.getCanvasIfEdit?.fun&&detailData?.getCanvasIfEdit?.fun() > 0
|
detailData?.getCanvasIfEdit?.fun&&detailData?.getCanvasIfEdit?.fun() > 0
|
||||||
){
|
){
|
||||||
Modal.confirm({
|
resolve()
|
||||||
title: t('collectionModal.jsContent6'),
|
// Modal.confirm({
|
||||||
icon: createVNode(ExclamationCircleOutlined),
|
// title: t('collectionModal.jsContent6'),
|
||||||
okText: 'Yes',
|
// icon: createVNode(ExclamationCircleOutlined),
|
||||||
cancelText: 'No',
|
// okText: 'Yes',
|
||||||
mask:false,
|
// cancelText: 'No',
|
||||||
centered:true,
|
// mask:false,
|
||||||
onOk() {
|
// centered:true,
|
||||||
resolve(true)
|
// onOk() {
|
||||||
emit('canvasReload')
|
// resolve(true)
|
||||||
},
|
// emit('canvasReload')
|
||||||
onCancel(){
|
// },
|
||||||
resolve(false)
|
// onCancel(){
|
||||||
}
|
// resolve(false)
|
||||||
});
|
// }
|
||||||
|
// });
|
||||||
}else{
|
}else{
|
||||||
resolve(true)
|
resolve(true)
|
||||||
if(detailData.selectDetail.id !== item.id){
|
if(detailData.selectDetail.id !== item.id){
|
||||||
emit('canvasReload')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then((rv)=>{
|
}).then((rv)=>{
|
||||||
@@ -117,7 +117,6 @@ export default defineComponent({
|
|||||||
const maxObj = detailData.designDetail.clothes.find(item => item.priority === maxValue);
|
const maxObj = detailData.designDetail.clothes.find(item => item.priority === maxValue);
|
||||||
store.commit('DesignDetail/setDesignColthes',maxObj.id)
|
store.commit('DesignDetail/setDesignColthes',maxObj.id)
|
||||||
}
|
}
|
||||||
emit('canvasReload')
|
|
||||||
emit('deleteItem')
|
emit('deleteItem')
|
||||||
}
|
}
|
||||||
const addSketch = ()=>{
|
const addSketch = ()=>{
|
||||||
@@ -268,17 +267,8 @@ export default defineComponent({
|
|||||||
let allPostition = store.state.Workspace.workspaceAllPosition
|
let allPostition = store.state.Workspace.workspaceAllPosition
|
||||||
return allPostition.find(item => item.value === type)?.name
|
return allPostition.find(item => item.value === type)?.name
|
||||||
}
|
}
|
||||||
let observers = null as any
|
|
||||||
onMounted(()=>{
|
|
||||||
observers = new ResizeObserver(entries => {
|
|
||||||
for (let entry of entries) {
|
|
||||||
setItemPosition()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
observers.observe(detailData.modelNavBox);
|
|
||||||
})
|
|
||||||
onBeforeUnmount(()=>{
|
onBeforeUnmount(()=>{
|
||||||
observers.disconnect();
|
|
||||||
})
|
})
|
||||||
return{
|
return{
|
||||||
...toRefs(detailData),
|
...toRefs(detailData),
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="molepositon" :class="{active:!imgDesignImg}">
|
<div class="molepositon" :class="{active:!imgDesignImg}">
|
||||||
<div class="designOpenrtion_imgMask" v-if="frontBack?.body?.path" :style="frontBack?.body?.style">
|
<div class="designOpenrtion_imgMask" v-if="frontBack?.body?.path" :style="frontBack?.body?.style">
|
||||||
<div class="designOpenrtion_print" v-for="item,index in frontBack.back" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))" @click="setpitch(item,index)" :style="frontBack.front[index].style">
|
<div class="designOpenrtion_print" v-for="item,index in frontBack.back" :style="frontBack.front[index].style">
|
||||||
<img :style="item.imageUrl?'':'display:none;'" :src="item.imageUrl" alt="">
|
<img :style="item.imageUrl?'':'display:none;'" :src="item.imageUrl" alt="">
|
||||||
</div>
|
</div>
|
||||||
<img class="perview_img" @load="setPrintSize()" ref="detailBody" :key="designDetail.designItemId" :src="frontBack?.body?.path" :style="'width:'+ frontBack?.body?.layersObject?.[0].imageSize?.[0] +';height:' + frontBack?.body?.layersObject?.[0].imageSize?.[0] +';'">
|
<img class="perview_img" @load="setPrintSize()" ref="detailBody" :key="designDetail.designItemId" :src="frontBack?.body?.path" :style="'width:'+ frontBack?.body?.layersObject?.[0].imageSize?.[0] +';height:' + frontBack?.body?.layersObject?.[0].imageSize?.[0] +';'">
|
||||||
<div class="detail_modal_item_front" v-for="item,index in frontBack.front" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))" @click="setpitch(item,index)" :style="item.style">
|
<!-- <div class="detail_modal_item_front" ref="target" v-for="item,index in frontBack.front" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))" @click="setpitch(item,index)" :style="item.style">
|
||||||
|
<img :src="item.imageUrl" alt="">
|
||||||
|
</div> -->
|
||||||
|
<div class="detail_modal_item_front" :ref="el => { setElementRef(el, index) }" v-for="item,index in frontBack.front" :class="{'active':item.id == selectDetail?.id}" :style="item.style">
|
||||||
<img :src="item.imageUrl" alt="">
|
<img :src="item.imageUrl" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="designOpenrtion_btnBox">
|
<div ref="moveableContainer" class="moveableContainer"></div>
|
||||||
<ul v-for="item,index in frontBack.front" :key="item" :class="{active:item.designOpenrtionBtn}" class="designOpenrtion_btn" :style="item.style" @mousedown.stop="itemMoveMousedown(index,getMousePosition($event,false))" @touchstart.passive="itemMoveMousedown(index,getMousePosition($event,true))">
|
|
||||||
<li class="designOpenrtion_btn_top" @mousedown.stop="itemSizeMousedown('top',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('top',getMousePosition($event,true))"></li>
|
|
||||||
<li class="designOpenrtion_btn_bottom" @mousedown.stop="itemSizeMousedown('bottom',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('bottom',getMousePosition($event,true))"></li>
|
|
||||||
<li class="designOpenrtion_btn_left" @mousedown.stop="itemSizeMousedown('left',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('left',getMousePosition($event,true))"></li>
|
|
||||||
<li class="designOpenrtion_btn_right" @mousedown.stop="itemSizeMousedown('right',getMousePosition($event,false))" @touchstart.passive="itemSizeMousedown('right',getMousePosition($event,true))"></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="designOpenrtion_imgMask" v-if="!frontBack?.body?.path">
|
<div class="designOpenrtion_imgMask" v-if="!frontBack?.body?.path">
|
||||||
<img :src="selectDetail?.undividedLayerWithSinglePrint || selectDetail?.undividedLayer || selectDetail?.path" style="object-fit: cover;" alt="">
|
<img :src="selectDetail?.undividedLayerWithSinglePrint || selectDetail?.undividedLayer || selectDetail?.path" style="object-fit: cover;" alt="">
|
||||||
@@ -40,8 +36,10 @@ import { Https } from "@/tool/https";
|
|||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { getMousePosition } from "@/tool/mdEvent";
|
import { getMousePosition } from "@/tool/mdEvent";
|
||||||
import { Modal,message } from 'ant-design-vue';
|
import Vue3Moveable from 'vue3-moveable';
|
||||||
import newFollowVue from '@/component/Account/message/newFollow.vue';
|
import Moveable from 'moveable';
|
||||||
|
import { parse } from 'vue/compiler-sfc';
|
||||||
|
import { scale } from 'echarts/types/src/scale/helper.js';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components:{
|
||||||
},
|
},
|
||||||
@@ -51,7 +49,7 @@ export default defineComponent({
|
|||||||
type:Boolean,
|
type:Boolean,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits:['canvasReload','addSketch','modelOnLoad'],
|
emits:['addSketch'],
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -75,10 +73,7 @@ export default defineComponent({
|
|||||||
imgDom:null as any,
|
imgDom:null as any,
|
||||||
direction:'',
|
direction:'',
|
||||||
})
|
})
|
||||||
watch(()=>selectItem.selectDetail,(newValue,oldValue)=>{
|
|
||||||
if(!newValue && newValue?.id == oldValue?.id)return
|
|
||||||
selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
|
|
||||||
},{immediate: true,})
|
|
||||||
watch(()=>detailData.frontBack?.body?.path,(newVal)=>{
|
watch(()=>detailData.frontBack?.body?.path,(newVal)=>{
|
||||||
setPrintSize()
|
setPrintSize()
|
||||||
})
|
})
|
||||||
@@ -99,7 +94,6 @@ export default defineComponent({
|
|||||||
if(entries[0].contentRect.width == 0)return
|
if(entries[0].contentRect.width == 0)return
|
||||||
detailData.observerWH.width = Math.floor(entries[0].contentRect.width)
|
detailData.observerWH.width = Math.floor(entries[0].contentRect.width)
|
||||||
detailData.observerWH.height = Math.floor(entries[0].contentRect.height)
|
detailData.observerWH.height = Math.floor(entries[0].contentRect.height)
|
||||||
console.log(detailData.observerWH)
|
|
||||||
})
|
})
|
||||||
detailData.observer.observe(dom)
|
detailData.observer.observe(dom)
|
||||||
|
|
||||||
@@ -131,6 +125,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
for (const key in detailData.frontBack.back[index].style) {
|
for (const key in detailData.frontBack.back[index].style) {
|
||||||
if(key == 'zIndex')return
|
if(key == 'zIndex')return
|
||||||
|
if(key == 'transform')return
|
||||||
let value = detailData.frontBack.back[index].style[key]
|
let value = detailData.frontBack.back[index].style[key]
|
||||||
if(typeof value !== 'number'){
|
if(typeof value !== 'number'){
|
||||||
value = value.replace('px','')
|
value = value.replace('px','')
|
||||||
@@ -142,7 +137,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
emit('modelOnLoad')
|
initMoveableForSelected()
|
||||||
},500);
|
},500);
|
||||||
};
|
};
|
||||||
img.src = detailData.frontBack?.body?.path;
|
img.src = detailData.frontBack?.body?.path;
|
||||||
@@ -150,203 +145,280 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
const getDetailListDom = reactive({
|
const getDetailListDom = reactive({
|
||||||
libraryList:null as any,
|
libraryList:null as any,
|
||||||
|
moveableContainer:null as any,//控件层
|
||||||
})
|
})
|
||||||
|
|
||||||
//设置尺寸
|
const elementRefs = ref([]) as any;
|
||||||
const itemSizeMousedown = (direction:any,event:any)=>{
|
const moveableInstance = ref(null) as any;
|
||||||
selectItem.direction = direction
|
const setElementRef = (el, index) => {
|
||||||
selectItem.imgDom = document.getElementsByClassName('molepositon')[0].getElementsByClassName("detail_modal_item_front")[selectItem.imgDomIndex]
|
elementRefs.value[index] = el;
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].designOpenrtionBtn = true
|
};
|
||||||
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
|
const updateRect = ()=>{
|
||||||
let li = (document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_btn_top")[0] as any).offsetWidth/2
|
setTimeout(() => {
|
||||||
if(selectItem.direction == 'right' || selectItem.direction == 'bottom'){
|
moveableInstance.value.updateRect()
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].centers.left = imgDomWH.x+event.offsetX-li
|
}, 500);
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].centers.top = imgDomWH.y+event.offsetY-li
|
}
|
||||||
}else{
|
const initMoveableForSelected = () => {
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].centers.left = imgDomWH.x+event.offsetX+imgDomWH.width-li
|
// 销毁旧的实例
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].centers.top = imgDomWH.y+event.offsetY+imgDomWH.height-li
|
if(selectItem.imgDomIndex == -1)return
|
||||||
|
if (moveableInstance.value) {
|
||||||
|
moveableInstance.value.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('mousemove', sizeMouseMove);
|
const selectedEl = elementRefs.value[selectItem.imgDomIndex];
|
||||||
document.addEventListener('touchmove', sizeTouchmove);
|
if (!selectedEl) return;
|
||||||
document.addEventListener('mouseup', sizeMouseup);
|
if(!selectedEl.style.left)return
|
||||||
document.addEventListener('touchend', sizeMouseup);
|
moveableInstance.value = new Moveable(getDetailListDom.moveableContainer, {
|
||||||
}
|
target: selectedEl,
|
||||||
const sizeMouseMove = (event:any)=>{
|
draggable: true,
|
||||||
let e = getMousePosition(event,false)
|
scalable: true,
|
||||||
sizeMouseMoveOperation(e)
|
rotatable: true,
|
||||||
}
|
keepRatio: false, // 等比缩放
|
||||||
const sizeTouchmove = (event:any)=>{
|
snappable: true,
|
||||||
let e = getMousePosition(event,true)
|
snapThreshold: 5,
|
||||||
sizeMouseMoveOperation(e)
|
edge: false,
|
||||||
|
});
|
||||||
}
|
let startPosition = {//记录初始位置
|
||||||
const sizeMouseup = (e:any)=>{
|
left: 0,
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style={
|
top: 0,
|
||||||
right:'auto',
|
|
||||||
left:selectItem.imgDom.offsetLeft+'px',
|
|
||||||
bottom:'auto',
|
|
||||||
top:selectItem.imgDom.offsetTop+'px',
|
|
||||||
height:selectItem.imgDom.offsetHeight+'px',
|
|
||||||
width:selectItem.imgDom.offsetWidth+'px',
|
|
||||||
zIndex:selectItem.imgDom.style.zIndex,
|
|
||||||
// zIndex:selectItem.printZIndex
|
|
||||||
}
|
}
|
||||||
// detailData.frontBack.back[selectItem.imgDomIndex].style.zIndex = selectItem.printZIndex
|
moveableInstance.value.on('scaleStart', ({ target, direction }) => {
|
||||||
document.removeEventListener('mousemove',sizeMouseMove)
|
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
|
||||||
document.removeEventListener('touchmove',sizeTouchmove)
|
if (!frontStyle.mirror){
|
||||||
document.removeEventListener('mouseup',sizeMouseup)
|
let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/);
|
||||||
document.removeEventListener('touchend',sizeMouseup)
|
let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/);
|
||||||
//鼠标抬起
|
frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false };
|
||||||
setRevocation()
|
}
|
||||||
}
|
});
|
||||||
let isMove = false//表示是否移动,是否需要在鼠标抬起的时候保存数据
|
moveableInstance.value.on('rotateStart', ({ target, direction }) => {
|
||||||
|
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
|
||||||
|
if (!frontStyle.mirror){
|
||||||
|
let scaleX = frontStyle.style.transform.match(/scaleX\(([-\d.]+)\)/);
|
||||||
|
let scaleY = frontStyle.style.transform.match(/scaleY\(([-\d.]+)\)/);
|
||||||
|
frontStyle.mirror = { x: scaleX[1] == '-1' ? true : false, y: scaleY[1] == '-1' ? true : false };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
moveableInstance.value.on('dragStart', ({ target, clientX, clientY }) => {
|
||||||
|
startPosition = {
|
||||||
|
left:parseFloat(selectedEl.style.left.replace('px','')) || 0,
|
||||||
|
top:parseFloat(selectedEl.style.top.replace('px','')) || 0,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 拖拽
|
||||||
|
moveableInstance.value.on('drag', ({ target, beforeTranslate }) => {
|
||||||
|
let x = startPosition.left + beforeTranslate[0]
|
||||||
|
let y = startPosition.top + beforeTranslate[1]
|
||||||
|
detailData.frontBack.front[selectItem.imgDomIndex].style.left = x + 'px'
|
||||||
|
detailData.frontBack.front[selectItem.imgDomIndex].style.top = y + 'px'
|
||||||
|
});
|
||||||
|
const updateElementTransform = (element, rotateDeg = null) => {
|
||||||
|
|
||||||
|
const currentTransform = element.style?.transform || '';
|
||||||
|
// 1. 提取当前的所有rotate
|
||||||
|
const currentRotates = (currentTransform.match(/rotate[XYZ]?\([^)]+\)/g) || []);
|
||||||
|
// 2. 获取除镜像和rotate外的其他所有变换
|
||||||
|
let otherTransforms = currentTransform
|
||||||
|
.replace(/scaleX\(-1\)|scaleY\(-1\)/g, '') // 移除镜像
|
||||||
|
.replace(/rotate[XYZ]?\([^)]+\)/g, '') // 移除rotate
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim();
|
||||||
|
// 3. 构建新transform
|
||||||
|
const transforms = [];
|
||||||
|
// 镜像部分
|
||||||
|
if (element.mirror.x) transforms.push('scaleX(-1)');
|
||||||
|
if (element.mirror.y) transforms.push('scaleY(-1)');
|
||||||
|
if (otherTransforms) transforms.push(otherTransforms);
|
||||||
|
if (rotateDeg !== null) {
|
||||||
|
transforms.push(`rotate(${rotateDeg}deg)`);
|
||||||
|
} else if (currentRotates.length > 0) {
|
||||||
|
transforms.push(...currentRotates);
|
||||||
|
}
|
||||||
|
element.style.transform = transforms.join(' ').trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
moveableInstance.value.on('scale', ({ target, delta, direction }) => {
|
||||||
|
const frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
|
||||||
|
if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false };
|
||||||
|
|
||||||
|
const width = parseFloat(frontStyle.style.width);
|
||||||
|
const height = parseFloat(frontStyle.style.height);
|
||||||
|
let left = parseFloat(frontStyle.style.left) || 0;
|
||||||
|
let top = parseFloat(frontStyle.style.top) || 0;
|
||||||
|
let rotation = 0;
|
||||||
|
// 获取原始比例
|
||||||
|
const originalRatio = width / height;
|
||||||
|
if (frontStyle.style.transform) {
|
||||||
|
const transform = frontStyle.style.transform;
|
||||||
|
const match = transform.match(/rotate\(([-\d.]+)deg\)/);
|
||||||
|
if (match) {
|
||||||
|
rotation = parseFloat(match[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 根据旋转角度重新计算控制点的方向
|
||||||
|
function getAdjustedCorner(originalCorner, rotationAngle) {
|
||||||
|
const angleRad = rotationAngle * (Math.PI / 180);
|
||||||
|
const cosA = Math.cos(angleRad);
|
||||||
|
const sinA = Math.sin(angleRad);
|
||||||
|
const newX = originalCorner.x * cosA - originalCorner.y * sinA;
|
||||||
|
const newY = originalCorner.x * sinA + originalCorner.y * cosA;
|
||||||
|
const threshold = 0.5;
|
||||||
|
return {
|
||||||
|
x: Math.abs(newX) > threshold ? (newX > 0 ? 1 : -1) : 0,
|
||||||
|
y: Math.abs(newY) > threshold ? (newY > 0 ? 1 : -1) : 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rotation !== 0) {
|
||||||
|
direction = getAdjustedCorner({x: direction[0], y: direction[1]}, rotation);
|
||||||
|
direction = [direction.x, direction.y];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是对角线方向(需要等比缩放)
|
||||||
|
const isDiagonal = Math.abs(direction[0]) === 1 && Math.abs(direction[1]) === 1;
|
||||||
|
|
||||||
|
// 处理轴缩放,包含镜像翻转逻辑
|
||||||
|
const processAxis = (axis, val, deltaVal, dir, originalPosition, originalSize, keepRatio = false, otherAxisResult = null) => {
|
||||||
|
let newVal = val * deltaVal;
|
||||||
|
const mirrorKey = axis === 'width' ? 'x' : 'y';
|
||||||
|
const isWidth = axis === 'width';
|
||||||
|
|
||||||
|
// 检查是否需要镜像翻转(当值小于等于0时)
|
||||||
|
if (newVal <= 0) {
|
||||||
|
frontStyle.mirror[mirrorKey] = !frontStyle.mirror[mirrorKey];
|
||||||
|
newVal = Math.abs(newVal);
|
||||||
|
|
||||||
|
updateElementTransform(frontStyle);
|
||||||
|
|
||||||
|
// 镜像翻转后,位置需要根据原始锚点调整
|
||||||
|
if (dir === -1) {
|
||||||
|
// 从左上/右上缩放时,位置保持不变
|
||||||
|
return {
|
||||||
|
newVal,
|
||||||
|
adjustPos: originalPosition,
|
||||||
|
shouldFlip: true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// 从左下/右下缩放时,位置需要调整
|
||||||
|
const newPosition = originalPosition + (originalSize - newVal) * (frontStyle.mirror[mirrorKey] ? -1 : 1);
|
||||||
|
return {
|
||||||
|
newVal,
|
||||||
|
adjustPos: newPosition,
|
||||||
|
shouldFlip: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const shouldMove = (!frontStyle.mirror[mirrorKey] && dir === -1) ||
|
||||||
|
(frontStyle.mirror[mirrorKey] && dir === 1);
|
||||||
|
if (keepRatio && otherAxisResult) {
|
||||||
|
newVal = isWidth ?
|
||||||
|
otherAxisResult.newVal * originalRatio :
|
||||||
|
otherAxisResult.newVal / originalRatio;
|
||||||
|
}
|
||||||
|
let adjustPos;
|
||||||
|
if (shouldMove) {
|
||||||
|
adjustPos = originalPosition - (newVal - originalSize);
|
||||||
|
} else {
|
||||||
|
adjustPos = originalPosition;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
newVal,
|
||||||
|
adjustPos,
|
||||||
|
shouldFlip: false
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 自由缩放
|
||||||
|
const widthResult = processAxis('width', width, delta[0], direction[0], left, width);
|
||||||
|
const heightResult = processAxis('height', height, delta[1], direction[1], top, height);
|
||||||
|
|
||||||
|
frontStyle.style.left = widthResult.adjustPos + 'px';
|
||||||
|
frontStyle.style.top = heightResult.adjustPos + 'px';
|
||||||
|
frontStyle.style.width = widthResult.newVal + 'px';
|
||||||
|
frontStyle.style.height = heightResult.newVal + 'px';
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
// 旋转
|
||||||
|
moveableInstance.value.on('rotate', ({ target, beforeRotate }) => {
|
||||||
|
let frontStyle = detailData.frontBack.front[selectItem.imgDomIndex];
|
||||||
|
// 确保镜像状态存在
|
||||||
|
if (!frontStyle.mirror) frontStyle.mirror = { x: false, y: false };
|
||||||
|
|
||||||
|
const { x: isMirroredX, y: isMirroredY } = frontStyle.mirror;
|
||||||
|
|
||||||
|
// 计算实际旋转角度
|
||||||
|
let actualRotate = beforeRotate;
|
||||||
|
|
||||||
|
// 关键逻辑:当镜像状态不同时(一个true一个false),旋转方向反转
|
||||||
|
if (isMirroredX !== isMirroredY) {
|
||||||
|
actualRotate = -beforeRotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保角度在 0-360 度范围内
|
||||||
|
actualRotate = actualRotate % 360;
|
||||||
|
|
||||||
|
// 如果角度为负数,转换为正数
|
||||||
|
if (actualRotate < 0) {
|
||||||
|
actualRotate += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保角度在 [0, 360) 范围内
|
||||||
|
actualRotate = ((actualRotate % 360) + 360) % 360;
|
||||||
|
|
||||||
|
updateElementTransform(frontStyle, actualRotate.toFixed(2));
|
||||||
|
});
|
||||||
|
// 调整大小
|
||||||
|
moveableInstance.value.on('resize', ({ target, width, height }) => {
|
||||||
|
// console.log(width, height)
|
||||||
|
// detailData.frontBack.front[selectItem.imgDomIndex].style.width = width
|
||||||
|
// detailData.frontBack.front[selectItem.imgDomIndex].style.height = height
|
||||||
|
});
|
||||||
|
moveableInstance.value.on('dragEnd', ({ target, clientX, clientY }) => {
|
||||||
|
startPosition = {
|
||||||
|
left:0,
|
||||||
|
top:0,
|
||||||
|
}
|
||||||
|
upDataDetail()
|
||||||
|
});
|
||||||
|
moveableInstance.value.on('scaleEnd', () => {
|
||||||
|
upDataDetail()
|
||||||
|
});
|
||||||
|
moveableInstance.value.on('rotateEnd', () => {
|
||||||
|
upDataDetail()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
watch(()=>selectItem.selectDetail,(newValue,oldValue)=>{
|
||||||
|
if(!newValue && newValue?.id == oldValue?.id)return
|
||||||
|
selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == newValue.id)
|
||||||
|
initMoveableForSelected()
|
||||||
|
},{immediate: true,})
|
||||||
|
|
||||||
const setRevocation = ()=>{
|
const setRevocation = ()=>{
|
||||||
if(!isMove)return
|
|
||||||
isMove = false
|
|
||||||
let frontBack = JSON.parse(JSON.stringify(detailData.frontBack))
|
let frontBack = JSON.parse(JSON.stringify(detailData.frontBack))
|
||||||
console.log(frontBack)
|
|
||||||
let revocation:any = JSON.parse((sessionStorage.getItem("revocation") as any))
|
let revocation:any = JSON.parse((sessionStorage.getItem("revocation") as any))
|
||||||
revocation.push({designData:null,position:frontBack})
|
revocation.push({designData:null,position:frontBack})
|
||||||
sessionStorage.setItem('revocation', JSON.stringify(revocation));
|
sessionStorage.setItem('revocation', JSON.stringify(revocation));
|
||||||
|
|
||||||
}
|
}
|
||||||
const sizeMouseMoveOperation = (e:any)=> {
|
const upDataDetail = async ()=>{
|
||||||
isMove = true
|
//同步到selectDetail数据中,
|
||||||
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
|
// getDetailListData.designDetail
|
||||||
let parentNode =selectItem.imgDom.parentNode
|
let {scale,offset,priority,transpose,rotate,position,imageSize} = await getSubmitData(selectItem.selectDetail)
|
||||||
let width = imgDomWH.width
|
selectItem.selectDetail.layersObject[0].scale = scale
|
||||||
let height = imgDomWH.height
|
selectItem.selectDetail.layersObject[1].scale = scale
|
||||||
let w,h
|
selectItem.selectDetail.layersObject[0].offset = offset
|
||||||
let num = height/width
|
selectItem.selectDetail.layersObject[1].offset = offset
|
||||||
//判断移动四个边
|
selectItem.selectDetail.layersObject[0].priority = priority
|
||||||
if(selectItem.direction == 'right'){
|
selectItem.selectDetail.layersObject[1].priority = priority
|
||||||
w = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)
|
selectItem.selectDetail.layersObject[0].rotate = rotate
|
||||||
h = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)*num
|
selectItem.selectDetail.layersObject[1].rotate = rotate
|
||||||
width = w+'px'
|
selectItem.selectDetail.layersObject[0].transpose = transpose
|
||||||
// height = w*num+'px'
|
selectItem.selectDetail.layersObject[1].transpose = transpose
|
||||||
}else if(selectItem.direction == 'top'){
|
selectItem.selectDetail.layersObject[0].position = position
|
||||||
num = width/height
|
selectItem.selectDetail.layersObject[1].position = position
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.top = 'auto'
|
selectItem.selectDetail.layersObject[0].imageSize = imageSize
|
||||||
// this.printStyleList[selectItem.imgDomIndex].style.left = 'auto'
|
selectItem.selectDetail.layersObject[1].imageSize = imageSize
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.bottom = parentNode.offsetHeight -imgDomWH.height - selectItem.imgDom.offsetTop+'px'
|
|
||||||
w = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)*num
|
|
||||||
h = (detailData.frontBack.front[selectItem.imgDomIndex].centers.top - e.clientY)
|
|
||||||
|
|
||||||
height = h+'px'
|
|
||||||
// width = h*num+'px'
|
|
||||||
}else if(selectItem.direction == 'bottom'){
|
|
||||||
num = width/height
|
|
||||||
h = (e.clientY - detailData.frontBack.front[selectItem.imgDomIndex].centers.top)
|
|
||||||
height = h+'px'
|
|
||||||
// width = h*num+'px'
|
|
||||||
}else if(selectItem.direction == 'left'){
|
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.left = 'auto'
|
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.right = parentNode.offsetWidth -imgDomWH.width - selectItem.imgDom.offsetLeft+'px'
|
|
||||||
w = (detailData.frontBack.front[selectItem.imgDomIndex].centers.left - e.clientX)
|
|
||||||
|
|
||||||
width = w+'px'
|
|
||||||
// height = w*num+'px'
|
|
||||||
}
|
|
||||||
//判断尺寸是否到边
|
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.width = width
|
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.height = height
|
|
||||||
}
|
|
||||||
// 设置移动
|
|
||||||
const mouseMove = (event:any)=>{
|
|
||||||
let e = getMousePosition(event,false)
|
|
||||||
mouseMoveOperation(e)
|
|
||||||
}
|
|
||||||
const touchmove=(event:any)=>{
|
|
||||||
let e = getMousePosition(event,true)
|
|
||||||
mouseMoveOperation(e)
|
|
||||||
}
|
|
||||||
const mouseup = (e:any)=> {
|
|
||||||
document.removeEventListener('mousemove',mouseMove)
|
|
||||||
document.removeEventListener('touchmove',touchmove)
|
|
||||||
document.removeEventListener('mouseup',mouseup)
|
|
||||||
document.removeEventListener('touchend',mouseup)
|
|
||||||
///鼠标抬起
|
|
||||||
setRevocation()
|
setRevocation()
|
||||||
}
|
}
|
||||||
const mouseMoveOperation = (e:any)=>{
|
|
||||||
isMove = true
|
|
||||||
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
|
|
||||||
let parentNode = document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_imgMask")[0].getBoundingClientRect()
|
|
||||||
let x = (e.clientX - detailData.frontBack.front[selectItem.imgDomIndex].centers.left)+'px'
|
|
||||||
let y = ( e.clientY - detailData.frontBack.front[selectItem.imgDomIndex].centers.top)+'px'
|
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.left = x
|
|
||||||
detailData.frontBack.front[selectItem.imgDomIndex].style.top = y
|
|
||||||
}
|
|
||||||
const clothesOpenActive = (index:number)=>{
|
|
||||||
// this.designItemDetail.clothes.forEach((item)=>{
|
|
||||||
// item.clothesOpenItem = false
|
|
||||||
// })
|
|
||||||
// if(index != -1){
|
|
||||||
// this.designItemDetail.clothes[index].clothesOpenItem = true
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
const itemMoveMousedown = async (index:any,e:any)=>{
|
|
||||||
if(detailData.selectDetail.id != detailData.frontBack.front[index].id)return
|
|
||||||
let isModal = false
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
// if(
|
|
||||||
// detailData.isEditPattern.value &&
|
|
||||||
// selectItem.selectDetail?.id &&
|
|
||||||
// (detailData.frontBack.front[index].id != selectItem.selectDetail.id)
|
|
||||||
// ){
|
|
||||||
// isModal = true
|
|
||||||
// Modal.confirm({
|
|
||||||
// title: t('collectionModal.jsContent2'),
|
|
||||||
// icon: createVNode(ExclamationCircleOutlined),
|
|
||||||
// okText: 'Yes',
|
|
||||||
// cancelText: 'No',
|
|
||||||
// mask:false,
|
|
||||||
// centered:true,
|
|
||||||
// onOk() {
|
|
||||||
// resolve(true)
|
|
||||||
// isOpen = true
|
|
||||||
// },
|
|
||||||
// onCancel(){
|
|
||||||
// resolve(false)
|
|
||||||
// isOpen = false
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }else{
|
|
||||||
// if(detailData.frontBack.front[index].id != selectItem.selectDetail.id){
|
|
||||||
// isOpen = true
|
|
||||||
// }
|
|
||||||
// resolve(true)
|
|
||||||
// isModal = false
|
|
||||||
// }
|
|
||||||
resolve(true)
|
|
||||||
}).then((rv)=>{
|
|
||||||
})
|
|
||||||
// emit('canvasReload')
|
|
||||||
// store.commit('DesignDetail/setDesignColthes',detailData.frontBack.front[index].id)
|
|
||||||
if(isModal)return
|
|
||||||
store.commit('DesignDetail/setDesignColthes',detailData.frontBack.front[index].id)
|
|
||||||
selectItem.imgDomIndex = index
|
|
||||||
detailData.frontBack.front.forEach((v:any)=>{
|
|
||||||
v.designOpenrtionBtn = false
|
|
||||||
})
|
|
||||||
clothesOpenActive(index)
|
|
||||||
let event = e||window.event
|
|
||||||
selectItem.imgDom = document.getElementsByClassName('molepositon')[0].getElementsByClassName("detail_modal_item_front")[selectItem.imgDomIndex]
|
|
||||||
detailData.frontBack.front[index].designOpenrtionBtn = true
|
|
||||||
// detailData.frontBack.front[index].style.zIndex = selectItem.printZIndex++
|
|
||||||
// detailData.frontBack.back[index].style.zIndex = selectItem.printZIndex
|
|
||||||
let imgDomWH = selectItem.imgDom.getBoundingClientRect()
|
|
||||||
let left = Number(detailData.frontBack.front[index].style.left.replace(/px/g,''))
|
|
||||||
let top = Number(detailData.frontBack.front[index].style.top.replace(/px/g,''))
|
|
||||||
detailData.frontBack.front[index].centers.left = imgDomWH.x+event.offsetX-left
|
|
||||||
detailData.frontBack.front[index].centers.top = imgDomWH.y+event.offsetY-top
|
|
||||||
|
|
||||||
document.addEventListener('mousemove', mouseMove);
|
|
||||||
document.addEventListener('touchmove', touchmove);
|
|
||||||
document.addEventListener('mouseup', mouseup);
|
|
||||||
document.addEventListener('touchend', mouseup);
|
|
||||||
}
|
|
||||||
const sort = (arr:any)=>{
|
const sort = (arr:any)=>{
|
||||||
arr.sort((a:any, b:any) => {
|
arr.sort((a:any, b:any) => {
|
||||||
var a_num = a.style.zIndex;
|
var a_num = a.style.zIndex;
|
||||||
@@ -355,9 +427,9 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
const getSubmitData = (value:any,isNoComputed)=>{
|
const getSubmitData = async (value:any)=>{
|
||||||
let parentNode = document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_imgMask")[0].getBoundingClientRect()
|
let parentNode = document.getElementsByClassName('molepositon')[0].getElementsByClassName("designOpenrtion_imgMask")[0].getBoundingClientRect()
|
||||||
if(!detailData.frontBack?.body?.layersObject?.[0]?.imageSize || isNoComputed){
|
if(!detailData.frontBack?.body?.layersObject?.[0]?.imageSize){
|
||||||
return{
|
return{
|
||||||
scale:value.layersObject[0].scale,
|
scale:value.layersObject[0].scale,
|
||||||
offset:value.layersObject[0].offset,
|
offset:value.layersObject[0].offset,
|
||||||
@@ -365,6 +437,17 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ratio = detailData.frontBack.body.layersObject[0].imageSize[0]/parentNode.width
|
let ratio = detailData.frontBack.body.layersObject[0].imageSize[0]/parentNode.width
|
||||||
|
|
||||||
|
let scale = 0
|
||||||
|
let dom:any = document.querySelector('.molepositon .perview_img')
|
||||||
|
const img = new Image();
|
||||||
|
img.src = detailData.frontBack?.body?.path;
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
img.onload = () => {
|
||||||
|
scale = dom.parentNode.offsetWidth / img.width
|
||||||
|
resolve()
|
||||||
|
};
|
||||||
|
})
|
||||||
// let arr:any = sort(detailData.frontBack.front)
|
// let arr:any = sort(detailData.frontBack.front)
|
||||||
let arr:any = sort(JSON.parse(JSON.stringify(detailData.frontBack.front)))
|
let arr:any = sort(JSON.parse(JSON.stringify(detailData.frontBack.front)))
|
||||||
let num = 10
|
let num = 10
|
||||||
@@ -377,6 +460,8 @@ export default defineComponent({
|
|||||||
priority:'',
|
priority:'',
|
||||||
maskUrl:'',
|
maskUrl:'',
|
||||||
maskMinioUrl:'',
|
maskMinioUrl:'',
|
||||||
|
position:null,
|
||||||
|
imageSize:null,
|
||||||
}
|
}
|
||||||
let state = false
|
let state = false
|
||||||
for (let index = 0; index < arr.length; index++) {
|
for (let index = 0; index < arr.length; index++) {
|
||||||
@@ -384,13 +469,27 @@ export default defineComponent({
|
|||||||
state = true
|
state = true
|
||||||
let y = ((arr[index]?.style?.top.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[0])
|
let y = ((arr[index]?.style?.top.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[0])
|
||||||
let x = ((arr[index]?.style?.left.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[1])
|
let x = ((arr[index]?.style?.left.replace(/px/g,'')*ratio).toFixed(0) as any - arr[index]?.position[1])
|
||||||
|
let positionX = Number((arr[index]?.style?.left.replace(/px/g,'')/scale)).toFixed(2)
|
||||||
|
let positionY = Number((arr[index]?.style?.top.replace(/px/g,'')/scale)).toFixed(2)
|
||||||
|
let imageSizeW = Number((arr[index]?.style?.width.replace(/px/g,'')/scale)).toFixed(2)
|
||||||
|
let imageSizeH = Number((arr[index]?.style?.height.replace(/px/g,'')/scale)).toFixed(2)
|
||||||
|
|
||||||
let scaleWidth = arr[index]?.imageSize?Number(((arr[index]?.style?.width.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[0]/arr[index].scale[0])).toFixed(2)):1
|
let scaleWidth = arr[index]?.imageSize?Number(((arr[index]?.style?.width.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[0]/arr[index].scale[0])).toFixed(2)):1
|
||||||
let scaleHeight = arr[index]?.imageSize?Number(((arr[index]?.style?.height.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[1]/arr[index].scale[1])).toFixed(2)):1
|
let scaleHeight = arr[index]?.imageSize?Number(((arr[index]?.style?.height.replace(/px/g,'')*ratio)/(arr[index]?.imageSize[1]/arr[index].scale[1])).toFixed(2)):1
|
||||||
// let widthScale = (arr[index].style.width.replace(/px/g,'')/arr[index].style.height.replace(/px/g,'')).toFixed(2)
|
// let widthScale = (arr[index].style.width.replace(/px/g,'')/arr[index].style.height.replace(/px/g,'')).toFixed(2)
|
||||||
|
|
||||||
|
let transformStr = arr[index]?.style?.transform
|
||||||
|
let scaleX = transformStr.match(/scaleX\(([-\d.]+)\)/)
|
||||||
|
let scaleY = transformStr.match(/scaleY\(([-\d.]+)\)/)
|
||||||
|
let rotate = transformStr.match(/rotate\(([-\d.]+)deg\)/);
|
||||||
|
data.transpose = [parseFloat(scaleX?.[1] || 1),parseFloat(scaleY?.[1] || 1)]
|
||||||
|
data.rotate = parseFloat(rotate?.[1] || 0)
|
||||||
data.scale = [scaleWidth,scaleHeight]
|
data.scale = [scaleWidth,scaleHeight]
|
||||||
let top = y == 0 ? value.layersObject[0].offset[1]:y+value.layersObject[0].offset[1]
|
let top = y == 0 ? value.layersObject[0].offset[1]:y+value.layersObject[0].offset[1]
|
||||||
let left = x == 0 ? value.layersObject[0].offset[0]:x+value.layersObject[0].offset[0]
|
let left = x == 0 ? value.layersObject[0].offset[0]:x+value.layersObject[0].offset[0]
|
||||||
data.offset = [left?left:0,top?top:0]
|
data.offset = [left?left:0,top?top:0]
|
||||||
|
data.position = [positionY,positionX]
|
||||||
|
data.imageSize = [imageSizeW,imageSizeH]
|
||||||
// data.offset = [left?left:0,top?top:0]
|
// data.offset = [left?left:0,top?top:0]
|
||||||
data.maskUrl = arr[index].maskUrl
|
data.maskUrl = arr[index].maskUrl
|
||||||
data.maskMinioUrl = arr[index].maskMinioUrl
|
data.maskMinioUrl = arr[index].maskMinioUrl
|
||||||
@@ -410,15 +509,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
const deleteNav = ()=>{
|
const deleteNav = ()=>{
|
||||||
|
|
||||||
}
|
|
||||||
const setpitch = (item:any,index:any)=>{
|
|
||||||
detailData.frontBack.front.forEach((v:any)=>{
|
|
||||||
v.designOpenrtionBtn = false
|
|
||||||
})
|
|
||||||
detailData.frontBack.front[index].designOpenrtionBtn = true
|
|
||||||
// detailData.frontBack.front[index].style.zIndex = selectItem.printZIndex++
|
|
||||||
// detailData.frontBack.back[index].style.zIndex = selectItem.printZIndex
|
|
||||||
clothesOpenActive(index)
|
|
||||||
}
|
}
|
||||||
const updataPosition = ()=>{
|
const updataPosition = ()=>{
|
||||||
let url = detailData.frontBack?.body?.path
|
let url = detailData.frontBack?.body?.path
|
||||||
@@ -431,10 +521,12 @@ export default defineComponent({
|
|||||||
detailData.frontBack.front.forEach((item:any,index:number) => {
|
detailData.frontBack.front.forEach((item:any,index:number) => {
|
||||||
for (const key in item.style) {
|
for (const key in item.style) {
|
||||||
if(key == 'zIndex')return
|
if(key == 'zIndex')return
|
||||||
|
if(key == 'transform')return
|
||||||
item.style[key] = item.style[key]*sacle+'px'
|
item.style[key] = item.style[key]*sacle+'px'
|
||||||
}
|
}
|
||||||
for (const key in detailData.frontBack.back[index].style) {
|
for (const key in detailData.frontBack.back[index].style) {
|
||||||
if(key == 'zIndex')return
|
if(key == 'zIndex')return
|
||||||
|
if(key == 'transform')return
|
||||||
detailData.frontBack.back[index].style[key] = detailData.frontBack.back[index].style[key]*sacle+'px'
|
detailData.frontBack.back[index].style[key] = detailData.frontBack.back[index].style[key]*sacle+'px'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -445,20 +537,22 @@ export default defineComponent({
|
|||||||
if (detailData.observer) {
|
if (detailData.observer) {
|
||||||
detailData.observer.disconnect()
|
detailData.observer.disconnect()
|
||||||
}
|
}
|
||||||
|
if (moveableInstance.value) {
|
||||||
|
moveableInstance.value.destroy();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return{
|
return{
|
||||||
...toRefs(detailData),
|
...toRefs(detailData),
|
||||||
...toRefs(selectItem),
|
...toRefs(selectItem),
|
||||||
...toRefs(getDetailListDom),
|
...toRefs(getDetailListDom),
|
||||||
|
setElementRef,
|
||||||
|
|
||||||
setPrintSize,
|
setPrintSize,
|
||||||
itemSizeMousedown,
|
|
||||||
itemMoveMousedown,
|
|
||||||
deleteNav,
|
deleteNav,
|
||||||
setpitch,
|
|
||||||
getSubmitData,
|
getSubmitData,
|
||||||
getMousePosition,
|
getMousePosition,
|
||||||
updataPosition,
|
updataPosition,
|
||||||
|
updateRect,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -541,6 +635,17 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.moveableContainer{
|
||||||
|
:deep(.moveable-origin){
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
:deep(.moveable-control){
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
:deep(.moveable-rotation-control){
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
> .designOpenrtion_imgMask{
|
> .designOpenrtion_imgMask{
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
@@ -561,10 +666,15 @@ export default defineComponent({
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail_modal_item_front,.designOpenrtion_print{
|
.detail_modal_item_front,.designOpenrtion_print{
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
&.active{
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
img{
|
img{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
// height: ;
|
// height: ;
|
||||||
@@ -583,94 +693,6 @@ export default defineComponent({
|
|||||||
.designOpenrtion_print{
|
.designOpenrtion_print{
|
||||||
z-index: 1 !important;
|
z-index: 1 !important;
|
||||||
}
|
}
|
||||||
> .designOpenrtion_btnBox{
|
|
||||||
z-index: 99;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
left: 0;
|
|
||||||
ul{
|
|
||||||
list-style: none;
|
|
||||||
// width: 100%;
|
|
||||||
// height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 2px solid rgb(20, 188, 255);
|
|
||||||
padding: 0;
|
|
||||||
-webkit-user-drag: none;
|
|
||||||
user-select:none;
|
|
||||||
opacity: 0;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
li{
|
|
||||||
cursor: pointer;
|
|
||||||
// border-radius: 50%;
|
|
||||||
width: calc(2rem*1.2);
|
|
||||||
height: calc(2rem*1.2);
|
|
||||||
background-color: rgb(20, 188, 255);
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
&.active{
|
|
||||||
opacity: 1;
|
|
||||||
z-index: 999 !important;
|
|
||||||
li{
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.designOpenrtion_btn_top,.designOpenrtion_btn_bottom{
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%,-50%) ;
|
|
||||||
cursor: n-resize;
|
|
||||||
}
|
|
||||||
.designOpenrtion_btn_top{
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.designOpenrtion_btn_bottom{
|
|
||||||
top: 100%;
|
|
||||||
}
|
|
||||||
.designOpenrtion_btn_left,.designOpenrtion_btn_right{
|
|
||||||
top: 50%;
|
|
||||||
transform: translate(-50%,-50%) ;
|
|
||||||
cursor: e-resize;
|
|
||||||
}
|
|
||||||
.designOpenrtion_btn_left{
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.designOpenrtion_btn_right{
|
|
||||||
left: 100%;
|
|
||||||
}
|
|
||||||
.designOpenrtion_rotote{
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%,-50%);
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
.designOpenrtion_rotote::after{
|
|
||||||
position: absolute;
|
|
||||||
content: "";
|
|
||||||
background-color: #14bcff;
|
|
||||||
width: 2px;
|
|
||||||
height: 30px;
|
|
||||||
left: 50%;
|
|
||||||
bottom: 0;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
}
|
|
||||||
.designOpenrtion_rotote::before{
|
|
||||||
position: absolute;
|
|
||||||
content: "";
|
|
||||||
background-color: #14bcff;
|
|
||||||
top: calc(50% - 30px);
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%,-50%) ;
|
|
||||||
width: calc(1.5rem*1.2);
|
|
||||||
height: calc(1.5rem*1.2);
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1074,10 +1074,10 @@ export default defineComponent({
|
|||||||
const scrollTop = textarea.scrollTop
|
const scrollTop = textarea.scrollTop
|
||||||
|
|
||||||
// 2. 计算单行高度
|
// 2. 计算单行高度
|
||||||
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px
|
const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20 // 默认20px
|
||||||
|
|
||||||
// 3. 重置高度为1行
|
// 3. 重置高度为1行
|
||||||
textarea.style.height = lineHeight + 'px'
|
textarea.style.height = (parseInt(lineHeight)+4) + 'px'
|
||||||
|
|
||||||
// 4. 计算实际需要的高度
|
// 4. 计算实际需要的高度
|
||||||
const newHeight = Math.max(lineHeight, textarea.scrollHeight)
|
const newHeight = Math.max(lineHeight, textarea.scrollHeight)
|
||||||
|
|||||||
@@ -476,9 +476,9 @@ export default defineComponent({
|
|||||||
if(!textarea)return
|
if(!textarea)return
|
||||||
const scrollTop = textarea.scrollTop;
|
const scrollTop = textarea.scrollTop;
|
||||||
// 2. 计算单行高度
|
// 2. 计算单行高度
|
||||||
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px
|
const lineHeight:any = parseInt(getComputedStyle(textarea).lineHeight) || 20; // 默认20px
|
||||||
// 3. 重置高度为1行
|
// 3. 重置高度为1行
|
||||||
textarea.style.height = lineHeight + 'px';
|
textarea.style.height = (parseInt(lineHeight)+4) + 'px'
|
||||||
// 4. 计算实际需要的高度
|
// 4. 计算实际需要的高度
|
||||||
const newHeight = Math.max(lineHeight, textarea.scrollHeight);
|
const newHeight = Math.max(lineHeight, textarea.scrollHeight);
|
||||||
textarea.style.height = newHeight + 'px';
|
textarea.style.height = newHeight + 'px';
|
||||||
|
|||||||
@@ -132,7 +132,25 @@ export default defineComponent({
|
|||||||
url:rv.url,
|
url:rv.url,
|
||||||
designType:props.item.resData.designType || props.item.designType,
|
designType:props.item.resData.designType || props.item.designType,
|
||||||
}
|
}
|
||||||
props.list.unshift(rv)
|
rv.type_ = {
|
||||||
|
type1: "material",
|
||||||
|
type2: props.level1Type
|
||||||
|
}
|
||||||
|
if(props.level1Type == 'Printboard'){
|
||||||
|
let list = props.list.filter((v:any)=> v.type_?.type1 == "material")
|
||||||
|
list.unshift(rv)
|
||||||
|
store.commit("setPrintboardMaterialFiles", list);
|
||||||
|
}else if(props.level1Type == 'Sketchboard'){
|
||||||
|
let list = props.list.filter((v:any)=> v.type_?.type1 == "material")
|
||||||
|
list.unshift(rv)
|
||||||
|
store.commit("setSketchboardMaterialFiles", list);
|
||||||
|
}else if(props.level1Type == 'Moodleboard'){
|
||||||
|
let list = props.list.filter((v:any)=> v.type_?.type1 == "material")
|
||||||
|
list.unshift(rv)
|
||||||
|
store.commit("setMoodleboardMaterialFiles", list);
|
||||||
|
}else{
|
||||||
|
props.list.unshift(rv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).catch(res=>{
|
).catch(res=>{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
:isBackgroundChangeable="false"
|
:isBackgroundChangeable="false"
|
||||||
ref="editCanvas"></editCanvas>
|
ref="editCanvas"></editCanvas>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn">
|
<div class="btn" v-if="btnShow">
|
||||||
<div class="gallery_btn" @click="canvasSave" style="width: min-content;margin-top: auto;">{{ $t('exportModel.Save') }}</div>
|
<div class="gallery_btn" @click="canvasSave" style="width: min-content;margin-top: auto;">{{ $t('exportModel.Save') }}</div>
|
||||||
<div class="gallery_btn" @click="exportElement">{{ $t('exportModel.Export') }}</div>
|
<div class="gallery_btn" @click="exportElement">{{ $t('exportModel.Export') }}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -46,7 +46,11 @@ export default defineComponent({
|
|||||||
isSubmitCanvasJSON:{
|
isSubmitCanvasJSON:{
|
||||||
type:Boolean,
|
type:Boolean,
|
||||||
default:false
|
default:false
|
||||||
}
|
},
|
||||||
|
btnShow:{
|
||||||
|
type:Boolean,
|
||||||
|
default:true
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits:['submitBase64Data','canvasChangeGetJSON'],
|
emits:['submitBase64Data','canvasChangeGetJSON'],
|
||||||
setup(props,{emit}) {
|
setup(props,{emit}) {
|
||||||
@@ -99,6 +103,9 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
const submitBase64Data = (base64Data)=>{
|
||||||
|
return dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:true,isCropByBg:true})
|
||||||
|
}
|
||||||
const exportElement = ()=>{
|
const exportElement = ()=>{
|
||||||
dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:false,isCropByBg:true}).then((rv)=>{
|
dataDom.editCanvas.exportImage({isContainBg:true,isContainFixed:false,isCropByBg:true}).then((rv)=>{
|
||||||
downloadBase64Image(rv,'canvas')
|
downloadBase64Image(rv,'canvas')
|
||||||
@@ -174,6 +181,7 @@ export default defineComponent({
|
|||||||
canvasInit,
|
canvasInit,
|
||||||
exportElement,
|
exportElement,
|
||||||
changeCanvas,
|
changeCanvas,
|
||||||
|
submitBase64Data,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data(prop) {
|
data(prop) {
|
||||||
|
|||||||
@@ -1497,6 +1497,7 @@ export default {
|
|||||||
CompositeColorTip: '颜色:保留原图像饱和度,改变新图像颜色',
|
CompositeColorTip: '颜色:保留原图像饱和度,改变新图像颜色',
|
||||||
CompositeLuminosity: '亮度',
|
CompositeLuminosity: '亮度',
|
||||||
CompositeLuminosityTip: '亮度:保留原图像颜色,改变新图像亮度',
|
CompositeLuminosityTip: '亮度:保留原图像颜色,改变新图像亮度',
|
||||||
|
GarmentPartSelector: '服装部件选取',
|
||||||
},
|
},
|
||||||
speedList: {
|
speedList: {
|
||||||
High: '高级',
|
High: '高级',
|
||||||
|
|||||||
@@ -1547,7 +1547,8 @@ export default {
|
|||||||
'Color: Preserve the original image saturation and change the color of the new image',
|
'Color: Preserve the original image saturation and change the color of the new image',
|
||||||
CompositeLuminosity: 'Luminosity',
|
CompositeLuminosity: 'Luminosity',
|
||||||
CompositeLuminosityTip:
|
CompositeLuminosityTip:
|
||||||
'Luminosity: Preserve the original image color and change the luminosity of the new image'
|
'Luminosity: Preserve the original image color and change the luminosity of the new image',
|
||||||
|
GarmentPartSelector: 'Garment Part Selector',
|
||||||
},
|
},
|
||||||
speedList: {
|
speedList: {
|
||||||
High: 'High',
|
High: 'High',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {Module} from 'vuex'
|
import {Module} from 'vuex'
|
||||||
import {RootState} from '../index'
|
import {RootState} from '../index'
|
||||||
import { forEach } from 'jszip'
|
import { forEach } from 'jszip'
|
||||||
|
import { transform } from 'typescript'
|
||||||
|
|
||||||
interface DesignDetail{
|
interface DesignDetail{
|
||||||
designDetail:any,
|
designDetail:any,
|
||||||
@@ -53,12 +54,32 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
data.clothes.forEach((v:any,index:any)=>{
|
data.clothes.forEach((v:any,index:any)=>{
|
||||||
// if(!v?.partialDesignDTO){
|
// if(!v?.partialDesignDTO){
|
||||||
// }
|
// }
|
||||||
|
function isJSONString(str) {
|
||||||
|
try {
|
||||||
|
JSON.parse(str);
|
||||||
|
return true; // 解析成功,是有效的JSON字符串
|
||||||
|
} catch (e) {
|
||||||
|
return false; // 解析失败,不是有效的JSON字符串
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v?.printObject?.prints?.forEach((item:any) => {
|
||||||
|
console.log(item.object)
|
||||||
|
if(isJSONString(item.object)){
|
||||||
|
item.object = JSON.parse(item.object)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
v?.trims?.prints?.forEach((item:any) => {
|
||||||
|
if(isJSONString(item.object)){
|
||||||
|
item.object = JSON.parse(item.object)
|
||||||
|
}
|
||||||
|
});
|
||||||
for (let i = v.layersObject.length-1; i >= 0; i--) {
|
for (let i = v.layersObject.length-1; i >= 0; i--) {
|
||||||
v.layersObject[i].style = {
|
v.layersObject[i].style = {
|
||||||
top:v.layersObject[i].position?.[0],
|
top:v.layersObject[i].position?.[0],
|
||||||
left:v.layersObject[i].position?.[1],
|
left:v.layersObject[i].position?.[1],
|
||||||
width:v.layersObject[i].imageSize?.[0],
|
width:v.layersObject[i].imageSize?.[0],
|
||||||
height:v.layersObject[i].imageSize?.[1],
|
height:v.layersObject[i].imageSize?.[1],
|
||||||
|
transform:`rotate(${v.layersObject[i]?.rotate || 0}deg) scaleX(${v.layersObject[i].transpose?.[0] || 1}) scaleY(${v.layersObject[i].transpose?.[1] || 1})`,
|
||||||
}
|
}
|
||||||
v.layersObject[i].centers={
|
v.layersObject[i].centers={
|
||||||
left:0,
|
left:0,
|
||||||
@@ -69,16 +90,12 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
v.layersObject[i].designOpenrtionBtn = false
|
v.layersObject[i].designOpenrtionBtn = false
|
||||||
if(v.layersObject[i].imageCategory.indexOf("back") == -1){
|
if(v.layersObject[i].imageCategory.indexOf("back") == -1){
|
||||||
front[index] = v.layersObject[i]
|
front[index] = v.layersObject[i]
|
||||||
// front[index].style.zIndex = v.priority
|
front[index].style.zIndex = v.priority + 10
|
||||||
front[index].id = v.id
|
front[index].id = v.id
|
||||||
front[index].undividedLayer = v.undividedLayer
|
|
||||||
front[index].undividedLayerWithSinglePrint = v?.undividedLayerWithSinglePrint
|
|
||||||
}else{
|
}else{
|
||||||
back[index] = v.layersObject[i]
|
back[index] = v.layersObject[i]
|
||||||
back[index].style.zIndex = v.priority
|
back[index].style.zIndex = v.priority
|
||||||
back[index].id = v.id
|
back[index].id = v.id
|
||||||
back[index].undividedLayer = v.undividedLayer
|
|
||||||
back[index].undividedLayerWithSinglePrint = v?.undividedLayerWithSinglePrint
|
|
||||||
// back[index].style.zIndex = backIndex==0?v.layersObject[i]:backIndex++
|
// back[index].style.zIndex = backIndex==0?v.layersObject[i]:backIndex++
|
||||||
}
|
}
|
||||||
if(state.printZIndex < v.priority){
|
if(state.printZIndex < v.priority){
|
||||||
@@ -198,8 +215,8 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
printObject:null,
|
printObject:null,
|
||||||
trims:null,
|
trims:null,
|
||||||
type:null,
|
type:null,
|
||||||
undividedLayer:null,
|
transpose:[1,1],
|
||||||
undividedLayerWithSinglePrint:null,
|
rotate:0,
|
||||||
}
|
}
|
||||||
if(!state.currentDetailType)state.currentDetailType = 'sketch'
|
if(!state.currentDetailType)state.currentDetailType = 'sketch'
|
||||||
state.designDetail.clothes.forEach((item:any) => {
|
state.designDetail.clothes.forEach((item:any) => {
|
||||||
@@ -209,6 +226,28 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
});
|
});
|
||||||
state.selectDetail = data
|
state.selectDetail = data
|
||||||
},
|
},
|
||||||
|
canvasPreviewUpdata(state,{type,callBack}){
|
||||||
|
console.log(state.selectDetail,type)
|
||||||
|
// state.selectDetail.newDetail?.print?.forEach((item:any) => {
|
||||||
|
// state.selectDetail.printObject.prints = []
|
||||||
|
// state.selectDetail.printObject.push({
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
if(type == 'print' || type == 'all')state.selectDetail.printObject.prints = state.selectDetail.newDetail?.print
|
||||||
|
if(type == 'color' || type == 'all')state.selectDetail.color = {
|
||||||
|
...state.selectDetail.newDetail?.color,
|
||||||
|
...state.selectDetail.newDetail?.color?.rgba,
|
||||||
|
...state.selectDetail.newDetail?.color?.hsv,
|
||||||
|
}
|
||||||
|
console.log(state.selectDetail,type,state.selectDetail.newDetail)
|
||||||
|
if(type == 'element' || type == 'all')state.selectDetail.trims.prints = state.selectDetail.newDetail?.element
|
||||||
|
if(type == 'all'){
|
||||||
|
state.selectDetail.newDetail = {}
|
||||||
|
}else{
|
||||||
|
state.selectDetail.newDetail[type] = null
|
||||||
|
}
|
||||||
|
callBack()
|
||||||
|
},
|
||||||
async setPraeview(state,value){//preview
|
async setPraeview(state,value){//preview
|
||||||
let data = value?.rv || value
|
let data = value?.rv || value
|
||||||
let currentType = value?.currentType
|
let currentType = value?.currentType
|
||||||
@@ -228,12 +267,9 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
}else{
|
}else{
|
||||||
id_ = item.id
|
id_ = item.id
|
||||||
}
|
}
|
||||||
console.log(id_)
|
|
||||||
let el:any = document.querySelector('.molepositon .perview_img')
|
let el:any = document.querySelector('.molepositon .perview_img')
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
if(!state.frontBack?.body?.path){
|
if(!state.frontBack?.body?.path){
|
||||||
state.frontBack.front[0].undividedLayer = value.rv.clothes[0].undividedLayer
|
|
||||||
state.frontBack.front[0].undividedLayerWithSinglePrint = value.rv.clothes[0]?.undividedLayerWithSinglePrint
|
|
||||||
resolve('')
|
resolve('')
|
||||||
}
|
}
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
@@ -252,7 +288,8 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
left:item.layersObject[i].position?.[1] * scale + 'px',
|
left:item.layersObject[i].position?.[1] * scale + 'px',
|
||||||
width:item.layersObject[i].imageSize?.[0] * scale + 'px',
|
width:item.layersObject[i].imageSize?.[0] * scale + 'px',
|
||||||
height:item.layersObject[i].imageSize?.[1] * scale + 'px',
|
height:item.layersObject[i].imageSize?.[1] * scale + 'px',
|
||||||
zIndex:v?.style?.zIndex?v.style.zIndex:v.priority?v.priority:state.frontBack.front.length
|
zIndex:v?.style?.zIndex?v.style.zIndex:v.priority?v.priority:state.frontBack.front.length,
|
||||||
|
transform:`rotate(${item.layersObject?.[i]?.rotate || 0}deg) scaleX(${item.layersObject[i].transpose?.[0] || 1}) scaleY(${item.layersObject[i].transpose?.[1] || 1})`,
|
||||||
}
|
}
|
||||||
item.layersObject[i].centers={
|
item.layersObject[i].centers={
|
||||||
left:0,
|
left:0,
|
||||||
@@ -263,14 +300,10 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
state.frontBack.front[index] = item.layersObject[i]
|
state.frontBack.front[index] = item.layersObject[i]
|
||||||
// state.frontBack.front[index].style.zIndex = v.priority
|
// state.frontBack.front[index].style.zIndex = v.priority
|
||||||
state.frontBack.front[index].id = item.id
|
state.frontBack.front[index].id = item.id
|
||||||
state.frontBack.front[index].undividedLayer = item.undividedLayer
|
|
||||||
state.frontBack.front[index].undividedLayerWithSinglePrint = item?.undividedLayerWithSinglePrint
|
|
||||||
}else{
|
}else{
|
||||||
state.frontBack.back[index] = item.layersObject[i]
|
state.frontBack.back[index] = item.layersObject[i]
|
||||||
// state.frontBack.back[index].style.zIndex = v.priority
|
// state.frontBack.back[index].style.zIndex = v.priority
|
||||||
state.frontBack.back[index].id = item.id
|
state.frontBack.back[index].id = item.id
|
||||||
state.frontBack.back[index].undividedLayer = item.undividedLayer
|
|
||||||
state.frontBack.back[index].undividedLayerWithSinglePrint = item?.undividedLayerWithSinglePrint
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -293,6 +326,8 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
detailItem.minIOPath = item.minIOPath
|
detailItem.minIOPath = item.minIOPath
|
||||||
detailItem.scale = [1,1]
|
detailItem.scale = [1,1]
|
||||||
detailItem.offset = [0,0]
|
detailItem.offset = [0,0]
|
||||||
|
detailItem.transpose = item.transpose || [1,1]
|
||||||
|
detailItem.rotate = item.rotate || 0
|
||||||
detailItem.printObject = item.printObject
|
detailItem.printObject = item.printObject
|
||||||
detailItem.trims = item.trims
|
detailItem.trims = item.trims
|
||||||
detailItem.type = item.type
|
detailItem.type = item.type
|
||||||
@@ -307,8 +342,6 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
},
|
},
|
||||||
gradient:item.gradient,
|
gradient:item.gradient,
|
||||||
}
|
}
|
||||||
detailItem.undividedLayer = item.undividedLayer
|
|
||||||
detailItem.undividedLayerWithSinglePrint = item?.undividedLayerWithSinglePrint
|
|
||||||
if(detailItem.newDetail?.sketch?.id && !detailItem.id){
|
if(detailItem.newDetail?.sketch?.id && !detailItem.id){
|
||||||
state.designDetail.clothes.push(detailItem)
|
state.designDetail.clothes.push(detailItem)
|
||||||
}
|
}
|
||||||
@@ -354,8 +387,6 @@ const DesignDetail : Module<DesignDetail,RootState> = {
|
|||||||
// },
|
// },
|
||||||
// gradient:item.gradient,
|
// gradient:item.gradient,
|
||||||
// }
|
// }
|
||||||
// state.selectDetail.undividedLayer = item.undividedLayer
|
|
||||||
// state.selectDetail.undividedLayerWithSinglePrint = item?.undividedLayerWithSinglePrint
|
|
||||||
// if(state.selectDetail.newDetail?.sketch?.id && !state.selectDetail.id){
|
// if(state.selectDetail.newDetail?.sketch?.id && !state.selectDetail.id){
|
||||||
// state.designDetail.clothes.push(state.selectDetail)
|
// state.designDetail.clothes.push(state.selectDetail)
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -440,7 +440,10 @@ export const Https = {
|
|||||||
getHistoryNotification: `/api/message/getHistoryNotification`, //获取历史消息
|
getHistoryNotification: `/api/message/getHistoryNotification`, //获取历史消息
|
||||||
oneClickRead: `/api/message/oneClickRead`, //全部设为已读
|
oneClickRead: `/api/message/oneClickRead`, //全部设为已读
|
||||||
personalHomepage: `/api/account/personalHomepage`, //获取个人主页信息
|
personalHomepage: `/api/account/personalHomepage`, //获取个人主页信息
|
||||||
refreshMinioUrl: `/api/third/party/refreshMinioUrl` //获取可以使用的minio地址
|
refreshMinioUrl: `/api/third/party/refreshMinioUrl`, //获取可以使用的minio地址
|
||||||
|
|
||||||
|
// 画布
|
||||||
|
segAnything: `/api/python/segAnything`,//分割Anything
|
||||||
},
|
},
|
||||||
|
|
||||||
axiosGet(url, config) {
|
axiosGet(url, config) {
|
||||||
|
|||||||
@@ -618,6 +618,60 @@ function segmentImage(markerImage,fullImage,size){
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理PNG图片:透明度转白色,其他颜色转透明
|
||||||
|
* @param {string} sketchImage - 原始图片
|
||||||
|
* @returns {Promise} 处理后的ase64
|
||||||
|
*/
|
||||||
|
function sketchToMask(sketchImage) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.crossOrigin = 'anonymous';
|
||||||
|
img.onload = function() {
|
||||||
|
try {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
canvas.width = img.width;
|
||||||
|
canvas.height = img.height;
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
const data = imageData.data;
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
|
const r = data[i];
|
||||||
|
const g = data[i + 1];
|
||||||
|
const b = data[i + 2];
|
||||||
|
const a = data[i + 3];
|
||||||
|
if (a > 0) {
|
||||||
|
data[i] = 0;
|
||||||
|
data[i + 1] = 0;
|
||||||
|
data[i + 2] = 0;
|
||||||
|
data[i + 3] = 0;
|
||||||
|
} else {
|
||||||
|
// 完全透明的像素 -> 纯白色
|
||||||
|
data[i] = 255;
|
||||||
|
data[i + 1] = 255;
|
||||||
|
data[i + 2] = 255;
|
||||||
|
data[i + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.putImageData(imageData, 0, 0);
|
||||||
|
const base64 = canvas.toDataURL('image/png');
|
||||||
|
resolve(base64);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
img.onerror = function() {
|
||||||
|
reject(new Error('图片加载失败'));
|
||||||
|
};
|
||||||
|
|
||||||
|
img.src = sketchImage;
|
||||||
|
});
|
||||||
|
}
|
||||||
export {
|
export {
|
||||||
isEmail,
|
isEmail,
|
||||||
getUploadUrl,
|
getUploadUrl,
|
||||||
@@ -640,5 +694,6 @@ export {
|
|||||||
setGradual,
|
setGradual,
|
||||||
calculateGradientCoordinate,
|
calculateGradientCoordinate,
|
||||||
segmentImage,
|
segmentImage,
|
||||||
UrlToFile
|
UrlToFile,
|
||||||
|
sketchToMask
|
||||||
}
|
}
|
||||||