Reputation: 5052
I am implementing a whiteboard in an existing application, which is optimized for huge touch-screens (NEC display). The canvas itself is located in a widget, which is resizable, meaning the visible part of the canvas can vary from something of 400x500 px up to fullscreen size. However, only the viewport gets adjusted, the canvas is always fullscreen size in the beackround (and aligned to the top left corner of the widget), so the objects do not get distorted in size and ratio when changing de size of the widget. This means, when I render an image via canvas.toDataUrl('png')
, the image is always the same size.
Now we want to add a feature that the canvas itself gets scrollable, for easiness lets say its dimension is 3x3 fullscreens, meaning if you need more place, you can scroll one screen-size to the left or right resp. top or bottom. This is not difficult, but now we come to my question:
Is it possible to adjust the render-function, so that the image is not rendered from the whole canvas size, but rather the size of the "bounding box" of all elements resp. only selected elements? Here is an image to explain:
In this picture, the black square represents the acutal size of the canvas (and therefor the image which gets rendered), but I am searching a way to only render the red square (lets say all elements plus a padding of x pixels).
A really hacky way would be the following, but I am not sure if there is an easier way:
0+padding / 0+padding
Is there any other way of doing this?
Upvotes: 0
Views: 643
Reputation: 5052
For anyone who's interested, I've come up with the following solution. It's basically exactly what I sketched above, but would still be curious if there's an easier way.
renderSelection() {
const selectedObject = fabric.util.object.clone(this.canvas.getActiveObject());
const defaultPadding = 100;
this.dynamicCanvas = new fabric.Canvas('#dynamicCanvas', {
preserveObjectStacking: true
});
if ( selectedObject.type !== 'activeSelection') {
this.renderSingleSelectionDynamicCanvas(selectedObject, defaultPadding);
} else {
this.renderMultiSelectionCanvas(selectedObject, defaultPadding);
}
const renderedImage = this.dynamicCanvas.toDataURL('image/png');
}
renderSingleSelectionDynamicCanvas(selectedObject: any, defaultPadding: number) {
const totalWidth = selectedObject.width * selectedObject.scaleX;
const totalHeight = selectedObject.height * selectedObject.scaleY;
this.dynamicCanvas.setWidth(totalWidth + 2 * defaultPadding);
this.dynamicCanvas.setHeight(totalHeight + 2 * defaultPadding);
selectedObject.set({
left: defaultPadding,
top: defaultPadding
});
this.dynamicCanvas.add(selectedObject);
this.dynamicCanvas.renderAll();
}
renderMultiSelectionCanvas(multiSelectionObject: any, defaultPadding: number) {
const clonedObjects: Array<any> = [];
multiSelectionObject.forEachObject( obj => {
clonedObjects.push(fabric.util.object.clone(obj));
});
const group = new fabric.Group(clonedObjects, {
left: defaultPadding,
top: defaultPadding,
width: multiSelectionObject.width,
height: multiSelectionObject.height,
originX: multiSelectionObject.originX,
originY: multiSelectionObject.originY,
scaleX: multiSelectionObject.scaleX,
scaleY: multiSelectionObject.scaleY
});
const totalWidth = multiSelectionObject.width + 2 * defaultPadding;
const totalHeight = multiSelectionObject.height + 2 * defaultPadding;
this.dynamicCanvas.setWidth(totalWidth);
this.dynamicCanvas.setHeight(totalHeight);
this.dynamicCanvas.add(group);
this.dynamicCanvas.renderAll();
}
Upvotes: 1