mirror of
https://github.com/exogen/t2-model-skinner.git
synced 2026-01-19 11:14:45 +00:00
bump fabric
This commit is contained in:
parent
9e127b683c
commit
c1cc0c73a1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
docs/_next/static/chunks/6cb39dc61a422734.js
Normal file
1
docs/_next/static/chunks/6cb39dc61a422734.js
Normal file
File diff suppressed because one or more lines are too long
1
docs/_next/static/chunks/d63fc3798baf75bd.js
Normal file
1
docs/_next/static/chunks/d63fc3798baf75bd.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -11,7 +11,7 @@ f:"$Sreact.suspense"
|
|||
11:I[68027,[],"default"]
|
||||
:HL["/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","style"]
|
||||
:HL["/t2-model-skinner/_next/static/chunks/be25e0c53b3e76c3.css","style"]
|
||||
0:{"P":null,"b":"VY3oqBwyqvlStXl38ih2v","p":"/t2-model-skinner","c":["","gallery",""],"i":false,"f":[[["",{"children":["gallery",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["gallery",["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/be25e0c53b3e76c3.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/t2-model-skinner/_next/static/chunks/6d7b92f74fb4b5af.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/t2-model-skinner/_next/static/chunks/3710394f99078da4.js","async":true,"nonce":"$undefined"}]],["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"s":false,"S":true}
|
||||
0:{"P":null,"b":"-yFPMzbzcZfNmotCttmg4","p":"/t2-model-skinner","c":["","gallery",""],"i":false,"f":[[["",{"children":["gallery",{"children":["__PAGE__",{}]}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["gallery",["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/be25e0c53b3e76c3.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/t2-model-skinner/_next/static/chunks/6d7b92f74fb4b5af.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/t2-model-skinner/_next/static/chunks/3710394f99078da4.js","async":true,"nonce":"$undefined"}]],["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"s":false,"S":true}
|
||||
6:{}
|
||||
7:"$0:f:0:1:2:children:2:children:1:props:children:0:props:params"
|
||||
d:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -2,7 +2,7 @@
|
|||
2:I[39756,["/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","/t2-model-skinner/_next/static/chunks/7dd66bdf8a7e5707.js"],"default"]
|
||||
3:I[37457,["/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","/t2-model-skinner/_next/static/chunks/7dd66bdf8a7e5707.js"],"default"]
|
||||
4:I[47257,["/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","/t2-model-skinner/_next/static/chunks/7dd66bdf8a7e5707.js"],"ClientPageRoot"]
|
||||
5:I[52683,["/t2-model-skinner/_next/static/chunks/00e36f5c4a673582.js","/t2-model-skinner/_next/static/chunks/d9e502f7607fcfba.js","/t2-model-skinner/_next/static/chunks/ada16a90703ade36.js","/t2-model-skinner/_next/static/chunks/e4e6678c9c61c198.js","/t2-model-skinner/_next/static/chunks/a55df98dcb3b60ad.js"],"default"]
|
||||
5:I[52683,["/t2-model-skinner/_next/static/chunks/00e36f5c4a673582.js","/t2-model-skinner/_next/static/chunks/d63fc3798baf75bd.js","/t2-model-skinner/_next/static/chunks/a55df98dcb3b60ad.js","/t2-model-skinner/_next/static/chunks/6cb39dc61a422734.js","/t2-model-skinner/_next/static/chunks/ada16a90703ade36.js"],"default"]
|
||||
8:I[97367,["/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","/t2-model-skinner/_next/static/chunks/7dd66bdf8a7e5707.js"],"OutletBoundary"]
|
||||
a:I[11533,["/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","/t2-model-skinner/_next/static/chunks/7dd66bdf8a7e5707.js"],"AsyncMetadataOutlet"]
|
||||
c:I[97367,["/t2-model-skinner/_next/static/chunks/ff1a16fafef87110.js","/t2-model-skinner/_next/static/chunks/7dd66bdf8a7e5707.js"],"ViewportBoundary"]
|
||||
|
|
@ -11,7 +11,7 @@ f:"$Sreact.suspense"
|
|||
11:I[68027,[],"default"]
|
||||
:HL["/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","style"]
|
||||
:HL["/t2-model-skinner/_next/static/chunks/df18f9fdc6a3cb7c.css","style"]
|
||||
0:{"P":null,"b":"VY3oqBwyqvlStXl38ih2v","p":"/t2-model-skinner","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/df18f9fdc6a3cb7c.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/t2-model-skinner/_next/static/chunks/00e36f5c4a673582.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/t2-model-skinner/_next/static/chunks/d9e502f7607fcfba.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/t2-model-skinner/_next/static/chunks/ada16a90703ade36.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/t2-model-skinner/_next/static/chunks/e4e6678c9c61c198.js","async":true,"nonce":"$undefined"}],["$","script","script-4",{"src":"/t2-model-skinner/_next/static/chunks/a55df98dcb3b60ad.js","async":true,"nonce":"$undefined"}]],["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"s":false,"S":true}
|
||||
0:{"P":null,"b":"-yFPMzbzcZfNmotCttmg4","p":"/t2-model-skinner","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L4",null,{"Component":"$5","searchParams":{},"params":{},"promises":["$@6","$@7"]}],[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/df18f9fdc6a3cb7c.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/t2-model-skinner/_next/static/chunks/00e36f5c4a673582.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/t2-model-skinner/_next/static/chunks/d63fc3798baf75bd.js","async":true,"nonce":"$undefined"}],["$","script","script-2",{"src":"/t2-model-skinner/_next/static/chunks/a55df98dcb3b60ad.js","async":true,"nonce":"$undefined"}],["$","script","script-3",{"src":"/t2-model-skinner/_next/static/chunks/6cb39dc61a422734.js","async":true,"nonce":"$undefined"}],["$","script","script-4",{"src":"/t2-model-skinner/_next/static/chunks/ada16a90703ade36.js","async":true,"nonce":"$undefined"}]],["$","$L8",null,{"children":["$L9",["$","$La",null,{"promise":"$@b"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Lc",null,{"children":"$Ld"}],null],["$","$Le",null,{"children":["$","div",null,{"hidden":true,"children":["$","$f",null,{"fallback":null,"children":"$L10"}]}]}]]}],false]],"m":"$undefined","G":["$11",[["$","link","0",{"rel":"stylesheet","href":"/t2-model-skinner/_next/static/chunks/258ad065ddacdc6d.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"s":false,"S":true}
|
||||
6:{}
|
||||
7:"$0:f:0:1:2:children:1:props:children:0:props:params"
|
||||
d:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
||||
|
|
|
|||
2736
package-lock.json
generated
2736
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -20,7 +20,7 @@
|
|||
"@rc-component/slider": "^1.0.0",
|
||||
"@tanstack/react-query": "^5.90.5",
|
||||
"comlink": "^4.4.2",
|
||||
"fabric": "^5.5.2-browser",
|
||||
"fabric": "^6.7.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"globby": "^13.1.2",
|
||||
"jszip": "^3.10.1",
|
||||
|
|
@ -35,13 +35,10 @@
|
|||
"@eslint/js": "^9.38.0",
|
||||
"@next/bundle-analyzer": "^15.5.6",
|
||||
"@next/eslint-plugin-next": "^15.5.6",
|
||||
"@types/fabric": "^5.3.10",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/lodash.orderby": "^4.6.9",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@types/react": "^19.2.2",
|
||||
"@typescript-eslint/eslint-plugin": "^8.46.1",
|
||||
"@typescript-eslint/parser": "^8.46.1",
|
||||
"eslint": "^9.38.0",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.0",
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|||
import useCanvas from "./useCanvas";
|
||||
import useSettings from "./useSettings";
|
||||
import useTools from "./useTools";
|
||||
import { fabric } from "fabric";
|
||||
import { Canvas as FabricCanvas, InteractiveFabricObject } from "fabric";
|
||||
import { createFabricImage } from "./fabricUtils";
|
||||
|
||||
type JSONSnapshot = ReturnType<(typeof Canvas.prototype)["toDatalessJSON"]>;
|
||||
|
||||
function updateObjectControlOptions() {
|
||||
fabric.Object.prototype.set({
|
||||
InteractiveFabricObject.ownDefaults = {
|
||||
...InteractiveFabricObject.ownDefaults,
|
||||
transparentCorners: false,
|
||||
borderColor: "#8afff1",
|
||||
cornerSize: 9,
|
||||
|
|
@ -18,13 +19,13 @@ function updateObjectControlOptions() {
|
|||
cornerStrokeColor: "#1c9f7c",
|
||||
strokeWidth: 10,
|
||||
perPixelTargetFind: true,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export interface CanvasProps {
|
||||
canvasId: string;
|
||||
canvasType: "color" | "metallic";
|
||||
onChange: (canvas: fabric.Canvas) => void;
|
||||
onChange: (canvas: FabricCanvas) => void;
|
||||
baseImageUrl: string | null;
|
||||
textureSize: [number, number];
|
||||
defaultDrawingMode?: boolean;
|
||||
|
|
@ -38,7 +39,7 @@ export default function Canvas({
|
|||
defaultDrawingMode = false,
|
||||
}: CanvasProps) {
|
||||
const canvasElementRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const [canvas, setCanvas] = useState<fabric.Canvas | null>(null);
|
||||
const [canvas, setCanvas] = useState<FabricCanvas | null>(null);
|
||||
const { activeCanvas } = useTools();
|
||||
const { canvasPadding } = useSettings();
|
||||
const { registerCanvas, unregisterCanvas } = useCanvas();
|
||||
|
|
@ -105,13 +106,18 @@ export default function Canvas({
|
|||
const isActive = activeCanvas === canvasId;
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvasElementRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
preserveObjectStacking: true,
|
||||
targetFindTolerance: 2,
|
||||
};
|
||||
|
||||
updateObjectControlOptions();
|
||||
|
||||
const canvas = new fabric.Canvas(canvasElementRef.current, options);
|
||||
const canvas = new FabricCanvas(canvasElementRef.current, options);
|
||||
|
||||
let isSnapshotting = false;
|
||||
let changeTimer: ReturnType<typeof setTimeout>;
|
||||
|
|
@ -138,7 +144,7 @@ export default function Canvas({
|
|||
if (JSON.stringify(snapshot) === JSON.stringify(lastSnapshot)) {
|
||||
return history;
|
||||
} else {
|
||||
return [...history.slice(-5), snapshot];
|
||||
return [...history.slice(-10), snapshot];
|
||||
}
|
||||
});
|
||||
setRedoHistory([]);
|
||||
|
|
@ -225,6 +231,11 @@ export default function Canvas({
|
|||
canRedo,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
setUndoHistory([]);
|
||||
setRedoHistory([]);
|
||||
}, [canvas, baseImageUrl, textureSize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (canvas && textureSize) {
|
||||
trackChanges.current = false;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ export default function CanvasInteractions({
|
|||
className="CanvasInteractions"
|
||||
tabIndex={0}
|
||||
ref={ref}
|
||||
onDragOver={(event) => {
|
||||
event.preventDefault();
|
||||
}}
|
||||
onDrop={async (event) => {
|
||||
event.preventDefault();
|
||||
if (ref.current) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
import { InputHTMLAttributes, useEffect, useRef, useState } from "react";
|
||||
import { fabric } from "fabric";
|
||||
import { FabricImage } from "fabric";
|
||||
import useCanvas from "./useCanvas";
|
||||
import useTools from "./useTools";
|
||||
import {
|
||||
|
|
@ -168,7 +168,7 @@ export default function CanvasTools() {
|
|||
const hasSelection = selectedObjects.length > 0;
|
||||
|
||||
const selectionHasImages =
|
||||
selectedObjects.filter((object) => object instanceof fabric.Image).length >
|
||||
selectedObjects.filter((object) => object instanceof FabricImage).length >
|
||||
0;
|
||||
|
||||
const handleBackgroundColorChange: InputHTMLAttributes<HTMLInputElement>["onChange"] =
|
||||
|
|
@ -441,7 +441,7 @@ export default function CanvasTools() {
|
|||
all (
|
||||
{canvas?._objects
|
||||
.filter(
|
||||
(object) => object instanceof fabric.Image
|
||||
(object) => object instanceof FabricImage
|
||||
)
|
||||
.length.toLocaleString() ?? 0}
|
||||
)
|
||||
|
|
@ -561,7 +561,7 @@ export default function CanvasTools() {
|
|||
<label>
|
||||
Opacity:{" "}
|
||||
<strong>
|
||||
{contrast == null
|
||||
{opacity == null
|
||||
? "MULTIPLE VALUES"
|
||||
: `${Math.round((opacity ?? 1) * 100)}%`}
|
||||
</strong>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ export default function ColorCanvas({
|
|||
const handleChange = useCallback<CanvasProps["onChange"]>(
|
||||
async (canvas) => {
|
||||
const imageUrl = canvas.toDataURL({
|
||||
format: "png",
|
||||
multiplier: 1,
|
||||
top: canvasPadding,
|
||||
left: canvasPadding,
|
||||
width: textureSize[0],
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ export default function MetallicCanvas({
|
|||
async (canvas) => {
|
||||
runningChangeHandlers.current += 1;
|
||||
const imageUrl = canvas.toDataURL({
|
||||
format: "png",
|
||||
multiplier: 1,
|
||||
top: canvasPadding,
|
||||
left: canvasPadding,
|
||||
width: textureSize[0],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
"use client";
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { fabric } from "fabric";
|
||||
import {
|
||||
FabricImage,
|
||||
FabricObject,
|
||||
ActiveSelection,
|
||||
filters,
|
||||
PencilBrush,
|
||||
} from "fabric";
|
||||
import { ToolsContext } from "./useTools";
|
||||
import useCanvas from "./useCanvas";
|
||||
import useWarrior from "./useWarrior";
|
||||
|
|
@ -15,7 +21,7 @@ const { materials } = modelConfig;
|
|||
|
||||
const defaultTextureSize = [512, 512] as [number, number];
|
||||
|
||||
function lockObject(object: fabric.Object) {
|
||||
function lockObject(object: FabricObject) {
|
||||
object.lockMovementX = true;
|
||||
object.lockMovementY = true;
|
||||
object.lockScalingX = true;
|
||||
|
|
@ -23,7 +29,7 @@ function lockObject(object: fabric.Object) {
|
|||
object.lockRotation = true;
|
||||
}
|
||||
|
||||
function unlockObject(object: fabric.Object) {
|
||||
function unlockObject(object: FabricObject) {
|
||||
object.lockMovementX = false;
|
||||
object.lockMovementY = false;
|
||||
object.lockScalingX = false;
|
||||
|
|
@ -31,9 +37,7 @@ function unlockObject(object: fabric.Object) {
|
|||
object.lockRotation = false;
|
||||
}
|
||||
|
||||
function isActiveSelection(
|
||||
object: fabric.Object
|
||||
): object is fabric.ActiveSelection {
|
||||
function isActiveSelection(object: FabricObject): object is ActiveSelection {
|
||||
return object.type === "activeSelection";
|
||||
}
|
||||
|
||||
|
|
@ -106,14 +110,14 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
|
||||
const [backgroundColor, setBackgroundColor] = useState("magenta");
|
||||
const [lockedObjects, setLockedObjects] = useState(
|
||||
() => new Set<fabric.Object>()
|
||||
() => new Set<FabricObject>()
|
||||
);
|
||||
const [brushColor, setBrushColor] = useState(200);
|
||||
const [brushSize, setBrushSize] = useState(10);
|
||||
const [filterMap, setFilterMap] = useState(
|
||||
() => new Map<fabric.Object, ObjectFilters>()
|
||||
() => new Map<FabricObject, ObjectFilters>()
|
||||
);
|
||||
const [selectedObjects, setSelectedObjects] = useState<fabric.Object[]>(
|
||||
const [selectedObjects, setSelectedObjects] = useState<FabricObject[]>(
|
||||
() => []
|
||||
);
|
||||
|
||||
|
|
@ -131,7 +135,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
const { combineColorAndAlphaImageUrls } = useImageWorker();
|
||||
const { canvasPadding } = useSettings();
|
||||
const [filterChanges, setFilterChanges] = useState<
|
||||
Array<[fabric.Object, ObjectFilters]>
|
||||
Array<[FabricObject, ObjectFilters]>
|
||||
>(() => []);
|
||||
const [layerMode, setLayerMode] = useState("BaseLayer");
|
||||
|
||||
|
|
@ -147,7 +151,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
|
||||
const setFilter = useCallback(
|
||||
(name: keyof ObjectFilters, value: number) => {
|
||||
const filterChanges: Array<[fabric.Object, ObjectFilters]> = [];
|
||||
const filterChanges: Array<[FabricObject, ObjectFilters]> = [];
|
||||
const newFilterMap = new Map(filterMap);
|
||||
let applyObjects = selectedObjects;
|
||||
if (layerMode === "AllLayers") {
|
||||
|
|
@ -156,7 +160,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
applyObjects = canvas?._objects.slice(0, 1) ?? [];
|
||||
}
|
||||
for (const applyObject of applyObjects) {
|
||||
if (applyObject instanceof fabric.Image) {
|
||||
if (applyObject instanceof FabricImage) {
|
||||
const existingFilters = filterMap.get(applyObject) ?? {};
|
||||
const newFilters = { ...existingFilters, [name]: value };
|
||||
newFilterMap.set(applyObject, newFilters);
|
||||
|
|
@ -180,7 +184,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
applyObjects = canvas?._objects.slice(0, 1) ?? [];
|
||||
}
|
||||
applyObjects = applyObjects.filter(
|
||||
(object) => object instanceof fabric.Image
|
||||
(object) => object instanceof FabricImage
|
||||
);
|
||||
if (applyObjects.length) {
|
||||
const getValue = (i: number) =>
|
||||
|
|
@ -210,10 +214,10 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
return;
|
||||
}
|
||||
for (const [selectedObject, newFilters] of filterChanges) {
|
||||
if (selectedObject instanceof fabric.Image) {
|
||||
if (selectedObject instanceof FabricImage) {
|
||||
selectedObject.filters = [];
|
||||
if (activeCanvasType === "metallic") {
|
||||
const grayscaleFilter = new fabric.Image.filters.Grayscale();
|
||||
const grayscaleFilter = new filters.Grayscale();
|
||||
selectedObject.filters.push(grayscaleFilter);
|
||||
}
|
||||
for (const key in newFilters) {
|
||||
|
|
@ -222,28 +226,28 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
switch (key) {
|
||||
case "HueRotation":
|
||||
selectedObject.filters.push(
|
||||
new fabric.Image.filters.HueRotation({
|
||||
new filters.HueRotation({
|
||||
rotation: filterValue,
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "Saturation":
|
||||
selectedObject.filters.push(
|
||||
new fabric.Image.filters.Saturation({
|
||||
new filters.Saturation({
|
||||
saturation: filterValue,
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "Brightness":
|
||||
selectedObject.filters.push(
|
||||
new fabric.Image.filters.Brightness({
|
||||
new filters.Brightness({
|
||||
brightness: filterValue,
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "Contrast":
|
||||
selectedObject.filters.push(
|
||||
new fabric.Image.filters.Contrast({
|
||||
new filters.Contrast({
|
||||
contrast: filterValue,
|
||||
})
|
||||
);
|
||||
|
|
@ -292,7 +296,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
const bringForward = useCallback(async () => {
|
||||
const object = canvas.getActiveObject();
|
||||
if (object) {
|
||||
canvas.bringForward(object, true);
|
||||
canvas.bringObjectForward(object, true);
|
||||
notifyChange();
|
||||
}
|
||||
}, [canvas, notifyChange]);
|
||||
|
|
@ -304,7 +308,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
if (canvas._objects[0] === object || canvas._objects[1] === object) {
|
||||
return;
|
||||
}
|
||||
canvas.sendBackwards(object, true);
|
||||
canvas.sendObjectBackwards(object, true);
|
||||
notifyChange();
|
||||
}
|
||||
}, [canvas, notifyChange]);
|
||||
|
|
@ -333,7 +337,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
if (!image.filters) {
|
||||
image.filters = [];
|
||||
}
|
||||
const grayscaleFilter = new fabric.Image.filters.Grayscale();
|
||||
const grayscaleFilter = new filters.Grayscale();
|
||||
image.filters.push(grayscaleFilter);
|
||||
image.applyFilters();
|
||||
}
|
||||
|
|
@ -346,6 +350,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
}
|
||||
if (lastAddedImage) {
|
||||
canvas.setActiveObject(lastAddedImage);
|
||||
canvas.requestRenderAll();
|
||||
}
|
||||
},
|
||||
[textureSize, activeCanvasType, metallicCanvas, canvas, setDrawingMode]
|
||||
|
|
@ -354,9 +359,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
const duplicate = useCallback(async () => {
|
||||
const object = canvas.getActiveObject();
|
||||
if (object) {
|
||||
const copy = await new Promise<fabric.Object>((resolve) =>
|
||||
object.clone(resolve)
|
||||
);
|
||||
const copy = await object.clone();
|
||||
copy.set({
|
||||
top: (copy.top ?? 0) + 20,
|
||||
left: (copy.left ?? 0) + 20,
|
||||
|
|
@ -388,6 +391,8 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
const copyToMetallic = useCallback(async () => {
|
||||
if (activeCanvasType === "color" && metallicCanvas) {
|
||||
const colorImageUrl = canvas.toDataURL({
|
||||
format: "png",
|
||||
multiplier: 1,
|
||||
top: canvasPadding,
|
||||
left: canvasPadding,
|
||||
width: textureSize[0],
|
||||
|
|
@ -397,7 +402,7 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
if (!image.filters) {
|
||||
image.filters = [];
|
||||
}
|
||||
const grayscaleFilter = new fabric.Image.filters.Grayscale();
|
||||
const grayscaleFilter = new filters.Grayscale();
|
||||
image.filters.push(grayscaleFilter);
|
||||
image.applyFilters();
|
||||
metallicCanvas.centerObject(image);
|
||||
|
|
@ -450,6 +455,8 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
let outputImageUrl;
|
||||
|
||||
const colorImageUrl = colorCanvas.toDataURL({
|
||||
format: "png",
|
||||
multiplier: 1,
|
||||
top: canvasPadding,
|
||||
left: canvasPadding,
|
||||
width: textureSize[0],
|
||||
|
|
@ -458,6 +465,8 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
|
||||
if (metallicCanvas) {
|
||||
const metallicImageUrl = metallicCanvas.toDataURL({
|
||||
format: "png",
|
||||
multiplier: 1,
|
||||
top: canvasPadding,
|
||||
left: canvasPadding,
|
||||
width: textureSize[0],
|
||||
|
|
@ -676,12 +685,18 @@ export default function ToolsProvider({ children }: { children: ReactNode }) {
|
|||
|
||||
useEffect(() => {
|
||||
if (metallicCanvas) {
|
||||
if (!metallicCanvas.freeDrawingBrush) {
|
||||
metallicCanvas.freeDrawingBrush = new PencilBrush(metallicCanvas);
|
||||
}
|
||||
metallicCanvas.freeDrawingBrush.width = brushSize;
|
||||
}
|
||||
}, [metallicCanvas, brushSize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (metallicCanvas) {
|
||||
if (!metallicCanvas.freeDrawingBrush) {
|
||||
metallicCanvas.freeDrawingBrush = new PencilBrush(metallicCanvas);
|
||||
}
|
||||
metallicCanvas.freeDrawingBrush.color = `rgb(${brushColor}, ${brushColor}, ${brushColor})`;
|
||||
}
|
||||
}, [metallicCanvas, brushColor]);
|
||||
|
|
|
|||
|
|
@ -1,12 +1,6 @@
|
|||
"use client";
|
||||
import { fabric } from "fabric";
|
||||
import { FabricImage } from "fabric";
|
||||
|
||||
export async function createFabricImage(url: string) {
|
||||
const promise = new Promise<fabric.Image>((resolve) =>
|
||||
fabric.Image.fromURL(url, resolve, {
|
||||
crossOrigin: "anonymous",
|
||||
})
|
||||
);
|
||||
const img = await promise;
|
||||
const img = await FabricImage.fromURL(url, { crossOrigin: "anonymous" });
|
||||
return img;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
"use client";
|
||||
import React, { useContext } from "react";
|
||||
import { fabric } from "fabric";
|
||||
import { Canvas as FabricCanvas } from "fabric";
|
||||
|
||||
export interface CanvasInfo {
|
||||
canvas: fabric.Canvas;
|
||||
canvas: FabricCanvas;
|
||||
notifyChange: () => void;
|
||||
isDrawingMode: boolean;
|
||||
setDrawingMode: (isDrawingMode: boolean) => void;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
"use client";
|
||||
import React, { useContext } from "react";
|
||||
import { fabric } from "fabric";
|
||||
import { FabricObject } from "fabric";
|
||||
|
||||
interface ToolsContextValue {
|
||||
activeCanvas: string | null;
|
||||
activeCanvasType: string;
|
||||
setActiveCanvasType: (canvasType: string) => void;
|
||||
selectedObjects: Array<fabric.Object>;
|
||||
selectedObjects: Array<FabricObject>;
|
||||
brushSize: number;
|
||||
setBrushSize: (brushSize: number) => void;
|
||||
brushColor: number;
|
||||
|
|
@ -42,7 +42,7 @@ interface ToolsContextValue {
|
|||
name: string;
|
||||
format: string;
|
||||
}) => Promise<void>;
|
||||
lockedObjects: Set<fabric.Object>;
|
||||
lockedObjects: Set<FabricObject>;
|
||||
backgroundColor: string;
|
||||
setBackgroundColor: (backgroundColor: string) => void;
|
||||
selectedMaterialIndex: number;
|
||||
|
|
|
|||
5
types/fabric.d.ts
vendored
5
types/fabric.d.ts
vendored
|
|
@ -1,5 +0,0 @@
|
|||
/// <reference types="fabric" />
|
||||
declare module "fabric" {
|
||||
// Re-export the DT namespace as the module's export.
|
||||
export { fabric };
|
||||
}
|
||||
Loading…
Reference in a new issue