const startItem = frameData.children.find(c => c.id === connector.startItem?.id);
const endItem = frameData.children.find(c => c.id === connector.endItem?.id);
if (startItem && endItem) {
+ const startItemX = startItem.position?.x ?? 0;
+ const startItemY = startItem.position?.y ?? 0;
+ const endItemX = endItem.position?.x ?? 0;
+ const endItemY = endItem.position?.y ?? 0;
+
+ const points = [
+ {
+ x: startItemX,
+ y: startItemY,
+ },
+ {
+ x: endItemX,
+ y: endItemY,
+ }
+ ];
+
+ console.log('points', points);
+
+
const path: Path = {
type: 'path',
kind: 'line',
position: {
- x: startItem.position?.x ?? 0,
- y: startItem.position?.y ?? 0,
+ x: 0,
+ y: 0,
},
- // Relative to the position given above
- points: [
- // Start point
- {
- x: 0,
- y: 0,
- },
- // End point
- {
- x: endItem.position?.x ? endItem.position.x - (startItem.position?.x ?? 0) : 0,
- y: endItem.position?.y ? endItem.position.y - (startItem.position?.y ?? 0) : 0,
- },
- ],
+ points: points,
strokeColor: connector.style?.color ?? '#1a1a1a',
endMarker: connector.style?.endStrokeCap === 'arrow' ? 'arrow-head-line' : undefined
};
+
slide.elements.push(path);
}
}
* The algorithm should:
* 1. Find the bounding box of all the items in the slide
* 2. Scale all the items to fit within the bounding box which is the maximum size of the frame minus some padding
- * 3. Center the items in the frame
- * 4. Return the slides with the transformed items
+ * 3. Align the items top left in the neoboard frame
+ * 4. Return the slides with the transformed items
+ *
+ * Note that the points of a path are relative to the path position and not the frame position.
+ * Note that that all the coordinates coming in are in the miro coordinate system which is likely larger than the neoboard frame.
+ * Note that the miro coordinate system is top left based and the neoboard frame is too.
+ * Note that the coordinates in miro are the center of the item and not a corner.
*
* @param board The board with items which should be fitted into the frame's maximum size
+ * @returns The board with the items transformed to fit into the frame
*/
function fitItemsBestIntoFrame(board: Whiteboard): Whiteboard {
const neoboardPadding = 10;
}
};
- // Note that all the coordinates are relative to the top left corner of the frame and still in the miro coordinate system which is likely larger than the neoboard frame.
-
for (const slide of board.whiteboard.slides) {
const transformedSlide: Slide = {
elements: [],
};
- // The first step is to find the bounding box of all the slides items.
- let minX = Number.MAX_SAFE_INTEGER;
- let minY = Number.MAX_SAFE_INTEGER;
- let maxX = Number.MIN_SAFE_INTEGER;
- let maxY = Number.MIN_SAFE_INTEGER;
-
- for (const element of slide.elements) {
- if (element.type === 'shape' || element.type === 'image') {
- const x = element.position.x;
- const y = element.position.y;
- const width = element.width;
- const height = element.height;
-
- minX = Math.min(minX, x);
- minY = Math.min(minY, y);
- maxX = Math.max(maxX, x + width);
- maxY = Math.max(maxY, y + height);
- } else if (element.type === 'path') {
- // The points are relative to the position of the path
- const x = element.position.x;
- const y = element.position.y;
- const points = element.points;
-
- minX = Math.min(minX, x);
- minY = Math.min(minY, y);
- maxX = Math.max(maxX, x + Math.max(...points.map(p => p.x)));
- maxY = Math.max(maxY, y + Math.max(...points.map(p => p.y)));
+ // Find the bounding box of all the items in the slide
+ let minX = Number.MAX_VALUE;
+ let minY = Number.MAX_VALUE;
+ let maxX = Number.MIN_VALUE;
+ let maxY = Number.MIN_VALUE;
+
+ for (const item of slide.elements) {
+ if (item.type === 'shape' || item.type === 'image') {
+ const shape = item as Shape;
+ // Make sure that we deal with x and y being in the center of the shape and not the corner.
+ // This means the bounds of the shape itself are x - width / 2, y - height / 2, x + width / 2, y + height / 2
+
+
+ minX = Math.min(minX, shape.position.x - shape.width / 2);
+ minY = Math.min(minY, shape.position.y - shape.height / 2);
+ maxX = Math.max(maxX, shape.position.x + shape.width / 2);
+ maxY = Math.max(maxY, shape.position.y + shape.height / 2);
+ } else if (item.type === 'path') {
+ // We know that our paths are always relative to 0,0 as we set the position to 0,0
+ const path = item as Path;
+ for (const point of path.points) {
+ minX = Math.min(minX, point.x);
+ minY = Math.min(minY, point.y);
+ maxX = Math.max(maxX, point.x);
+ maxY = Math.max(maxY, point.y);
+ }
}
}
- // The second step is to scale all the elements to fill the frame which is (neoboardWhiteboardWidth - neoboardPadding) wide and (neoboardWhiteboardHeight - neoboardPadding) tall.
- // We treat the size we want to fit the grouped size of all the items in the slide.
- // We also want this group to be centered in the frame.
- const width = maxX - minX;
- const height = maxY - minY;
- const scale = Math.min((neoboardWhiteboardWidth - neoboardPadding) / width, (neoboardWhiteboardHeight - neoboardPadding) / height);
-
- for (const element of slide.elements) {
- if (element.type === 'shape' || element.type === 'image') {
- const x = (element.position.x - minX) * scale + neoboardPadding / 2;
- const y = (element.position.y - minY) * scale + neoboardPadding / 2;
- const width = element.width * scale;
- const height = element.height * scale;
-
- transformedSlide.elements.push({
- ...element,
- position: {
- x,
- y,
- },
- width,
- height,
- });
- } else if (element.type === 'path') {
- // The points are relative to the position of the path
- const x = (element.position.x - minX) * scale + neoboardPadding / 2;
- const y = (element.position.y - minY) * scale + neoboardPadding / 2;
- const points = element.points.map(p => ({
- x: p.x * scale,
- y: p.y * scale,
- }));
-
- transformedSlide.elements.push({
- ...element,
+ // Scale all the items to fit within the bounding box which is the maximum size of the frame minus some padding
+ const boundingBoxWidth = maxX - minX;
+ const boundingBoxHeight = maxY - minY;
+
+ const scale = Math.min((neoboardWhiteboardWidth - neoboardPadding) / boundingBoxWidth, (neoboardWhiteboardHeight - neoboardPadding) / boundingBoxHeight);
+
+ for (const item of slide.elements) {
+ if (item.type === 'shape' || item.type === 'image') {
+ const shape = item;
+ // Ensure we account for the fact that our coordinates are in the center of the shape currently but we require them to be at the top left
+ // This means we need to substract half of the width from the x and substract half of the height to the y
+ const transformedShape = {
+ ...shape,
position: {
- x,
- y,
+ x: (shape.position.x - minX - shape.width / 2) * scale + neoboardPadding,
+ y: (shape.position.y - minY - shape.height / 2) * scale + neoboardPadding,
},
- points,
- });
- } else {
- transformedSlide.elements.push(element);
+ width: shape.width * scale,
+ height: shape.height * scale,
+ };
+
+
+ transformedSlide.elements.push(transformedShape);
+ } else if (item.type === 'path') {
+ // We want to keep the path set as 0,0 and only scale the points as they are relative to the path position
+ const path = item as Path;
+ const transformedPath = {
+ ...path,
+ points: path.points.map(point => ({
+ x: (point.x - minX) * scale + neoboardPadding,
+ y: (point.y - minY) * scale + neoboardPadding,
+ }))
+ };
+
+ transformedSlide.elements.push(transformedPath);
}
}