fix: proper canvas size on frame export
This commit is contained in:
parent
2e1da5537d
commit
0c4d6fbe95
@ -1,9 +1,13 @@
|
||||
import rough from "roughjs/bin/rough";
|
||||
import { NonDeletedExcalidrawElement } from "../element/types";
|
||||
import { getCommonBounds, getElementAbsoluteCoords } from "../element/bounds";
|
||||
import {
|
||||
Bounds,
|
||||
getCommonBounds,
|
||||
getElementAbsoluteCoords,
|
||||
} from "../element/bounds";
|
||||
import { renderSceneToSvg, renderStaticScene } from "../renderer/renderScene";
|
||||
import {
|
||||
convertToExportPadding,
|
||||
convertToExportPadding as convertExportPadding,
|
||||
distance,
|
||||
expandToAspectRatio,
|
||||
isOnlyExportingSingleFrame,
|
||||
@ -61,19 +65,29 @@ export const exportToCanvas = async (
|
||||
);
|
||||
|
||||
const padding = !exportingWithFancyBackground
|
||||
? convertToExportPadding(exportPadding)
|
||||
? convertExportPadding(exportPadding)
|
||||
: getFancyBackgroundPadding(
|
||||
convertToExportPadding(exportPadding),
|
||||
convertExportPadding(exportPadding),
|
||||
FANCY_BG_INCLUDE_LOGO,
|
||||
);
|
||||
|
||||
const onlyExportingSingleFrame =
|
||||
isOnlyExportingSingleFrame(elements) && !exportingWithFancyBackground;
|
||||
const onlyExportingSingleFrame = isOnlyExportingSingleFrame(elements);
|
||||
|
||||
const [minX, minY, width, height] = !exportingWithFancyBackground
|
||||
? getCanvasSize(elements, padding, onlyExportingSingleFrame)
|
||||
: getCanvasSize(elements, padding, onlyExportingSingleFrame, {
|
||||
? getCanvasSize({
|
||||
elements,
|
||||
padding,
|
||||
onlyExportingSingleFrame,
|
||||
exportingWithFancyBackground,
|
||||
})
|
||||
: getCanvasSize({
|
||||
elements,
|
||||
padding,
|
||||
onlyExportingSingleFrame,
|
||||
exportingWithFancyBackground,
|
||||
opts: {
|
||||
aspectRatio: { width: 16, height: 9 },
|
||||
},
|
||||
});
|
||||
|
||||
const { canvas, scale = 1 } = createCanvas(width, height);
|
||||
@ -95,7 +109,10 @@ export const exportToCanvas = async (
|
||||
exportingWithFancyBackground &&
|
||||
appState.fancyBackgroundImageKey !== "solid"
|
||||
) {
|
||||
const commonBounds = getCommonBounds(elements);
|
||||
const commonBounds = getElementsSize({
|
||||
elements,
|
||||
onlyExportingSingleFrame,
|
||||
});
|
||||
const contentSize: Dimensions = {
|
||||
width: distance(commonBounds[0], commonBounds[2]),
|
||||
height: distance(commonBounds[1], commonBounds[3]),
|
||||
@ -131,9 +148,15 @@ export const exportToCanvas = async (
|
||||
? viewBackgroundColor
|
||||
: null,
|
||||
scrollX:
|
||||
-minX + (onlyExportingSingleFrame ? 0 : padding[3] + scrollXAdjustment),
|
||||
-minX +
|
||||
(onlyExportingSingleFrame && !exportingWithFancyBackground
|
||||
? 0
|
||||
: padding[3] + scrollXAdjustment),
|
||||
scrollY:
|
||||
-minY + (onlyExportingSingleFrame ? 0 : padding[0] + scrollYAdjustment),
|
||||
-minY +
|
||||
(onlyExportingSingleFrame && !exportingWithFancyBackground
|
||||
? 0
|
||||
: padding[0] + scrollYAdjustment),
|
||||
zoom: defaultAppState.zoom,
|
||||
shouldCacheIgnoreZoom: false,
|
||||
theme: appState.exportWithDarkMode ? THEME.DARK : THEME.LIGHT,
|
||||
@ -183,9 +206,9 @@ export const exportToSvg = async (
|
||||
);
|
||||
|
||||
const padding = !exportingWithFancyBackground
|
||||
? convertToExportPadding(exportPadding)
|
||||
? convertExportPadding(exportPadding)
|
||||
: getFancyBackgroundPadding(
|
||||
convertToExportPadding(exportPadding),
|
||||
convertExportPadding(exportPadding),
|
||||
FANCY_BG_INCLUDE_LOGO,
|
||||
);
|
||||
|
||||
@ -204,13 +227,23 @@ export const exportToSvg = async (
|
||||
}
|
||||
}
|
||||
|
||||
const onlyExportingSingleFrame =
|
||||
isOnlyExportingSingleFrame(elements) && !exportingWithFancyBackground;
|
||||
const onlyExportingSingleFrame = isOnlyExportingSingleFrame(elements);
|
||||
|
||||
const [minX, minY, width, height] = !exportingWithFancyBackground
|
||||
? getCanvasSize(elements, padding, onlyExportingSingleFrame)
|
||||
: getCanvasSize(elements, padding, onlyExportingSingleFrame, {
|
||||
? getCanvasSize({
|
||||
elements,
|
||||
padding,
|
||||
onlyExportingSingleFrame,
|
||||
exportingWithFancyBackground,
|
||||
})
|
||||
: getCanvasSize({
|
||||
elements,
|
||||
padding,
|
||||
onlyExportingSingleFrame,
|
||||
exportingWithFancyBackground,
|
||||
opts: {
|
||||
aspectRatio: { width: 16, height: 9 },
|
||||
},
|
||||
});
|
||||
|
||||
// initialize SVG root
|
||||
@ -244,8 +277,16 @@ export const exportToSvg = async (
|
||||
Scene.getScene(elements[0])?.getNonDeletedElements()?.length ===
|
||||
elements.length;
|
||||
|
||||
const offsetX = -minX + (onlyExportingSingleFrame ? 0 : padding[3]);
|
||||
const offsetY = -minY + (onlyExportingSingleFrame ? 0 : padding[0]);
|
||||
const offsetX =
|
||||
-minX +
|
||||
(onlyExportingSingleFrame && !exportingWithFancyBackground
|
||||
? 0
|
||||
: padding[3]);
|
||||
const offsetY =
|
||||
-minY +
|
||||
(onlyExportingSingleFrame && !exportingWithFancyBackground
|
||||
? 0
|
||||
: padding[0]);
|
||||
|
||||
const exportingFrame =
|
||||
isExportingWholeCanvas || !onlyExportingSingleFrame
|
||||
@ -297,7 +338,10 @@ export const exportToSvg = async (
|
||||
appState.fancyBackgroundImageKey &&
|
||||
appState.fancyBackgroundImageKey !== "solid"
|
||||
) {
|
||||
const commonBounds = getCommonBounds(elements);
|
||||
const commonBounds = getElementsSize({
|
||||
elements,
|
||||
onlyExportingSingleFrame,
|
||||
});
|
||||
const contentSize: Dimensions = {
|
||||
width: distance(commonBounds[0], commonBounds[2]),
|
||||
height: distance(commonBounds[1], commonBounds[3]),
|
||||
@ -342,17 +386,16 @@ export const exportToSvg = async (
|
||||
return svgRoot;
|
||||
};
|
||||
|
||||
// calculate smallest area to fit the contents in
|
||||
const getCanvasSize = (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
exportPadding: ExportPadding,
|
||||
onlyExportingSingleFrame: boolean,
|
||||
opts?: { aspectRatio: Dimensions },
|
||||
): [number, number, number, number] => {
|
||||
const getElementsSize = ({
|
||||
elements,
|
||||
onlyExportingSingleFrame,
|
||||
}: {
|
||||
elements: readonly NonDeletedExcalidrawElement[];
|
||||
onlyExportingSingleFrame: boolean;
|
||||
}): Bounds => {
|
||||
// we should decide if we are exporting the whole canvas
|
||||
// if so, we are not clipping elements in the frame
|
||||
// and therefore, we should not do anything special
|
||||
|
||||
const isExportingWholeCanvas =
|
||||
Scene.getScene(elements[0])?.getNonDeletedElements()?.length ===
|
||||
elements.length;
|
||||
@ -372,17 +415,37 @@ const getCanvasSize = (
|
||||
);
|
||||
}
|
||||
|
||||
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
|
||||
return getCommonBounds(elements);
|
||||
};
|
||||
|
||||
// calculate smallest area to fit the contents in
|
||||
const getCanvasSize = ({
|
||||
elements,
|
||||
padding,
|
||||
onlyExportingSingleFrame,
|
||||
exportingWithFancyBackground,
|
||||
opts,
|
||||
}: {
|
||||
elements: readonly NonDeletedExcalidrawElement[];
|
||||
padding: ExportPadding;
|
||||
onlyExportingSingleFrame: boolean;
|
||||
exportingWithFancyBackground: boolean;
|
||||
opts?: { aspectRatio: Dimensions };
|
||||
}): [number, number, number, number] => {
|
||||
const [minX, minY, maxX, maxY] = getElementsSize({
|
||||
elements,
|
||||
onlyExportingSingleFrame,
|
||||
});
|
||||
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
|
||||
if (onlyExportingSingleFrame) {
|
||||
if (onlyExportingSingleFrame && !exportingWithFancyBackground) {
|
||||
width = distance(minX, maxX);
|
||||
height = distance(minY, maxY);
|
||||
} else {
|
||||
width = distance(minX, maxX) + exportPadding[1] + exportPadding[3];
|
||||
height = distance(minY, maxY) + exportPadding[0] + exportPadding[2];
|
||||
width = distance(minX, maxX) + padding[1] + padding[3];
|
||||
height = distance(minY, maxY) + padding[0] + padding[2];
|
||||
}
|
||||
|
||||
if (opts?.aspectRatio) {
|
||||
@ -403,11 +466,15 @@ export const getExportSize = (
|
||||
scale: number,
|
||||
appState: AppState,
|
||||
): [number, number] => {
|
||||
const [, , width, height] = getCanvasSize(
|
||||
const [, , width, height] = getCanvasSize({
|
||||
elements,
|
||||
convertToExportPadding(exportPadding),
|
||||
isExportingWithFacnyBackground(appState, elements),
|
||||
).map((dimension) => Math.trunc(dimension * scale));
|
||||
padding: convertExportPadding(exportPadding),
|
||||
onlyExportingSingleFrame: isOnlyExportingSingleFrame(elements),
|
||||
exportingWithFancyBackground: isExportingWithFacnyBackground(
|
||||
appState,
|
||||
elements,
|
||||
),
|
||||
}).map((dimension) => Math.trunc(dimension * scale));
|
||||
|
||||
return [width, height];
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user