Fixes canvas re-renders
This commit is contained in:
parent
c0dcce7c82
commit
b87e05b1de
3 changed files with 59 additions and 10 deletions
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10,20A10,10,0,1,1,20,10,10.011,10.011,0,0,1,10,20ZM10,1.474A8.526,8.526,0,1,0,18.526,10,8.536,8.536,0,0,0,10,1.474Z"/><circle cx="10" cy="10" r="2.513"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10,20A10,10,0,1,1,20,10,10.011,10.011,0,0,1,10,20ZM10,1.483A8.517,8.517,0,1,0,18.517,10,8.526,8.526,0,0,0,10,1.483Z"/><circle cx="10" cy="10" r="3.747"/></svg>
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
|
@ -1 +1 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10,20A10,10,0,1,1,20,10,10.011,10.011,0,0,1,10,20ZM10,1.483A8.517,8.517,0,1,0,18.517,10,8.526,8.526,0,0,0,10,1.483Z"/><circle cx="10" cy="10" r="3.747"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10,20A10,10,0,1,1,20,10,10.011,10.011,0,0,1,10,20ZM10,1.474A8.526,8.526,0,1,0,18.526,10,8.536,8.536,0,0,0,10,1.474Z"/><circle cx="10" cy="10" r="2.513"/></svg>
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
|
@ -94,6 +94,12 @@ export const MediaEditor = ({
|
||||||
|
|
||||||
// Initial image load and Fabric canvas setup
|
// Initial image load and Fabric canvas setup
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// This is important. We can't re-run this function if we've already setup
|
||||||
|
// a canvas since Fabric doesn't like that.
|
||||||
|
if (fabricCanvas) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
setImage(img);
|
setImage(img);
|
||||||
|
@ -117,7 +123,7 @@ export const MediaEditor = ({
|
||||||
img.onload = noop;
|
img.onload = noop;
|
||||||
img.onerror = noop;
|
img.onerror = noop;
|
||||||
};
|
};
|
||||||
}, [canvasId, imageSrc, onClose]);
|
}, [canvasId, fabricCanvas, imageSrc, onClose]);
|
||||||
|
|
||||||
const history = useFabricHistory(fabricCanvas);
|
const history = useFabricHistory(fabricCanvas);
|
||||||
|
|
||||||
|
@ -142,7 +148,22 @@ export const MediaEditor = ({
|
||||||
ev => isCmdOrCtrl(ev) && ev.key === 't',
|
ev => isCmdOrCtrl(ev) && ev.key === 't',
|
||||||
() => setEditMode(EditMode.Text),
|
() => setEditMode(EditMode.Text),
|
||||||
],
|
],
|
||||||
[ev => isCmdOrCtrl(ev) && ev.key === 'z', () => history?.undo()],
|
[
|
||||||
|
ev => isCmdOrCtrl(ev) && ev.key === 'z',
|
||||||
|
() => {
|
||||||
|
if (history?.canUndo()) {
|
||||||
|
history?.undo();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ev => isCmdOrCtrl(ev) && ev.shiftKey && ev.key === 'z',
|
||||||
|
() => {
|
||||||
|
if (history?.canRedo()) {
|
||||||
|
history?.redo();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
[
|
[
|
||||||
ev => ev.key === 'Escape',
|
ev => ev.key === 'Escape',
|
||||||
() => {
|
() => {
|
||||||
|
@ -519,6 +540,7 @@ export const MediaEditor = ({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj.exitEditing();
|
||||||
obj.set(getTextStyleAttributes(textStyle, sliderValue));
|
obj.set(getTextStyleAttributes(textStyle, sliderValue));
|
||||||
fabricCanvas.requestRenderAll();
|
fabricCanvas.requestRenderAll();
|
||||||
}, [editMode, fabricCanvas, sliderValue, textStyle]);
|
}, [editMode, fabricCanvas, sliderValue, textStyle]);
|
||||||
|
@ -610,6 +632,8 @@ export const MediaEditor = ({
|
||||||
textStyle,
|
textStyle,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
|
|
||||||
// In an ideal world we'd use <ModalHost /> to get the nice animation benefits
|
// In an ideal world we'd use <ModalHost /> to get the nice animation benefits
|
||||||
// but because of the way IText is implemented -- with a hidden textarea -- to
|
// but because of the way IText is implemented -- with a hidden textarea -- to
|
||||||
// capture keyboard events, we can't use ModalHost since that traps focus, and
|
// capture keyboard events, we can't use ModalHost since that traps focus, and
|
||||||
|
@ -963,12 +987,12 @@ export const MediaEditor = ({
|
||||||
'MediaEditor__control--selected': editMode === EditMode.Text,
|
'MediaEditor__control--selected': editMode === EditMode.Text,
|
||||||
})}
|
})}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!fabricCanvas) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (editMode === EditMode.Text) {
|
if (editMode === EditMode.Text) {
|
||||||
setEditMode(undefined);
|
setEditMode(undefined);
|
||||||
|
const obj = fabricCanvas?.getActiveObject();
|
||||||
|
if (obj instanceof MediaEditorFabricIText) {
|
||||||
|
obj.exitEditing();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setEditMode(EditMode.Text);
|
setEditMode(EditMode.Text);
|
||||||
}
|
}
|
||||||
|
@ -1069,12 +1093,37 @@ export const MediaEditor = ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={!image || isSaving}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
if (!fabricCanvas) {
|
if (!fabricCanvas) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const renderedCanvas = fabricCanvas.toCanvasElement();
|
|
||||||
const data = await canvasToBytes(renderedCanvas);
|
setEditMode(undefined);
|
||||||
|
setIsSaving(true);
|
||||||
|
|
||||||
|
let data: Uint8Array;
|
||||||
|
try {
|
||||||
|
fabricCanvas.discardActiveObject();
|
||||||
|
fabricCanvas.setDimensions({
|
||||||
|
width: image.width,
|
||||||
|
height: image.height,
|
||||||
|
});
|
||||||
|
fabricCanvas.setZoom(1);
|
||||||
|
const renderedCanvas = fabricCanvas.toCanvasElement();
|
||||||
|
fabricCanvas.setDimensions({
|
||||||
|
width: imageState.width * zoom,
|
||||||
|
height: imageState.height * zoom,
|
||||||
|
});
|
||||||
|
fabricCanvas.setZoom(zoom);
|
||||||
|
data = await canvasToBytes(renderedCanvas);
|
||||||
|
} catch (err) {
|
||||||
|
onClose();
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
setIsSaving(false);
|
||||||
|
}
|
||||||
|
|
||||||
onDone(data);
|
onDone(data);
|
||||||
}}
|
}}
|
||||||
theme={Theme.Dark}
|
theme={Theme.Dark}
|
||||||
|
|
Loading…
Add table
Reference in a new issue