Skip to content

Commit

Permalink
Merge pull request #4560 from systeminit/feat(web)-Add-ability-to-dow…
Browse files Browse the repository at this point in the history
…nload-screenshot-of-your-canvas

feat(web): Add ability to download screenshot of your canvas
  • Loading branch information
stack72 authored Sep 12, 2024
2 parents 1bfab3d + 793ea89 commit 5f23073
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 8 deletions.
36 changes: 29 additions & 7 deletions app/web/src/components/ModelingDiagram/DiagramControls.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<div :class="clsx('absolute flex left-4 bottom-4 z-20 h-8')">
<div
v-tooltip="'Zoom Out'"
:class="getButtonClasses(zoomLevel <= MIN_ZOOM)"
@click="adjustZoom('down')"
>
Expand All @@ -10,9 +11,11 @@
<div
:class="
clsx(
'bg-white border-neutral-300 border text-black',
'dark:bg-black dark:text-white dark:border-black',
'w-20 mx-2 flex flex-col justify-center text-center cursor-pointer select-none',
themeClasses(
'bg-white border-neutral-300 text-black hover:border-black',
'bg-black text-white border-black hover:border-white',
),
'w-20 mx-2 rounded border flex flex-col justify-center text-center cursor-pointer select-none',
)
"
title="set zoom level"
Expand All @@ -33,13 +36,15 @@
</div>
<div
v-tooltip="'Zoom In'"
:class="getButtonClasses(zoomLevel >= MAX_ZOOM)"
@click="adjustZoom('up')"
>
<Icon name="plus" size="full" />
</div>
<div
v-tooltip="'Diagram Controls'"
class="ml-4"
:class="getButtonClasses(false)"
@click="emit('open:help')"
Expand All @@ -59,6 +64,15 @@
>
<Icon name="eye" size="full" />
</div>
<div
v-tooltip="'Generate Workspace Screenshot'"
class="ml-4"
:class="getButtonClasses(false)"
@click="emit('downloadCanvasScreenshot')"
>
<Icon name="download" size="full" />
</div>
</div>
</template>
Expand All @@ -71,6 +85,7 @@ import {
DropdownMenu,
DropdownMenuItem,
Icon,
themeClasses,
} from "@si/vue-lib/design-system";
import { MAX_ZOOM, MIN_ZOOM } from "./diagram_constants";
import { useDiagramContext } from "./ModelingDiagram.vue";
Expand All @@ -89,6 +104,7 @@ const displayModeTooltip = computed(() => ({
const emit = defineEmits<{
(e: "open:help"): void;
(e: "downloadCanvasScreenshot"): void;
}>();

const zoomMenuRef = ref<InstanceType<typeof DropdownMenu>>();
Expand All @@ -102,8 +118,11 @@ const roundedZoomPercent = computed(() => Math.round(zoomLevel.value * 100));

function getButtonClasses(isDisabled: boolean) {
return clsx(
tw`rounded-full p-1 bg-neutral-600 text-white`,
tw`dark:bg-neutral-200 dark:text-black`,
tw`rounded-full p-1 active:border`,
themeClasses(
"bg-neutral-600 text-white active:bg-neutral-200 active:text-black active:border-black",
"bg-neutral-200 text-black active:bg-neutral-700 active:text-white active:border-white",
),
isDisabled
? tw`cursor-not-allowed opacity-50`
: tw`cursor-pointer hover:scale-110`,
Expand All @@ -112,8 +131,11 @@ function getButtonClasses(isDisabled: boolean) {

function getInvertedButtonClasses(isDisabled: boolean) {
return clsx(
tw`rounded-full p-1 bg-neutral-200 text-black border border-black`,
tw`dark:bg-neutral-700 dark:text-white dark:border-white`,
tw`rounded-full p-1 border`,
themeClasses(
"bg-neutral-200 text-black border-black",
"bg-neutral-700 text-white border-white",
),
isDisabled
? tw`cursor-not-allowed opacity-50`
: tw`cursor-pointer hover:scale-110`,
Expand Down
59 changes: 58 additions & 1 deletion app/web/src/components/ModelingDiagram/ModelingDiagram.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ overflow hidden */
</div>
</div>

<DiagramControls @open:help="helpModalRef.open()" />
<DiagramControls
@open:help="helpModalRef.open()"
@downloadCanvasScreenshot="downloadCanvasScreenshot"
/>

<!-- MAIN V-STAGE -->
<v-stage
Expand Down Expand Up @@ -282,6 +285,7 @@ import {
toRaw,
} from "vue";
import { Stage as KonvaStage } from "konva/lib/Stage";
import Konva from "konva";
import * as _ from "lodash-es";
import { KonvaEventObject } from "konva/lib/Node";
import { Vector2d, IRect } from "konva/lib/types";
Expand Down Expand Up @@ -695,6 +699,59 @@ watch(
{ immediate: true },
);

function downloadCanvasScreenshot() {
const stage = stageRef.value.getNode() as Konva.Stage;
if (!stage || typeof stage.getLayers !== "function") return;

// Find the bounding box of all shapes on the stage
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;

stage.find("Shape, Text, Image").forEach((node) => {
const box = node.getClientRect();
minX = Math.min(minX, box.x);
minY = Math.min(minY, box.y);
maxX = Math.max(maxX, box.x + box.width);
maxY = Math.max(maxY, box.y + box.height);
});

// Add a small padding around the components on the graph (adjust as needed)
const padding = 10;
minX -= padding;
minY -= padding;
maxX += padding;
maxY += padding;

const width = maxX - minX;
const height = maxY - minY;

// Capture the content
const dataURL = stage.toDataURL({
x: minX,
y: minY,
width,
height,
pixelRatio: 10, // Increase for higher resolution
});

// Generate filename with current date
const currentDate = new Date();
const dateString = currentDate.toISOString().split("T")[0];
const fileName = `canvas-screenshot-${dateString}.png`;

// Create a link element
const link = document.createElement("a");
link.download = fileName;
link.href = dataURL;

// Trigger download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}

onBeforeUnmount(() => {
// this fires when you change the change set from the drop down
// which feels unexpected that this component is destroyed and recreated?
Expand Down

0 comments on commit 5f23073

Please sign in to comment.