Skip to content

Commit

Permalink
Model diagram render png (#5791)
Browse files Browse the repository at this point in the history
  • Loading branch information
mwdchang authored Dec 10, 2024
1 parent b9103eb commit 79c0dcb
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 22 deletions.
4 changes: 2 additions & 2 deletions packages/client/graph-scaffolder/src/core/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ export abstract class Renderer<V, E> extends EventEmitter {
}

initialize(element: HTMLDivElement): void {
this.chartSize.width = element.clientWidth;
this.chartSize.height = element.clientHeight;
this.chartSize.width = element.clientWidth || parseFloat(element.style.width);
this.chartSize.height = element.clientHeight || parseFloat(element.style.height);
this.svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.svgEl.style.userSelect = 'none';
removeChildren(element).appendChild(this.svgEl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import { AMRSchemaNames, type FeatureConfig } from '@/types/common';
import { StratifiedMatrix } from '@/types/Model';
import type { Model } from '@/types/Types';
import { observeElementSizeChange } from '@/utils/observer';
import { svgToImage } from '@/utils/svg';
const props = defineProps<{
model: Model;
Expand Down Expand Up @@ -122,11 +123,17 @@ async function renderGraph() {
// Sanity guard
if (mmt.value.templates.length === 0) return;
renderer = getModelRenderer(
mmt.value,
graphElement.value as HTMLDivElement,
stratifiedView.value === StratifiedView.Collapsed
);
// Abstract the container element so we can render off the DOM
let elem = graphElement.value;
if (props.featureConfig?.isPreview && graphElement.value) {
const originalElem = graphElement.value;
elem = document.createElement('div');
elem.style.width = `${originalElem.clientWidth}px`;
elem.style.height = `${originalElem.clientHeight}px`;
}
renderer = getModelRenderer(mmt.value, elem as HTMLDivElement, stratifiedView.value === StratifiedView.Collapsed);
if (renderer.constructor === NestedPetrinetRenderer && renderer.dims?.length) {
graphLegendLabels.value = renderer.dims;
graphLegendColors.value = renderer.depthColorList;
Expand All @@ -135,6 +142,41 @@ async function renderGraph() {
graphLegendColors.value = [];
}
// If interactive, setup events and handlers
if (!props.featureConfig?.isPreview) {
makeGraphInteractive(renderer);
}
// Prepare data
const graphData = convertToIGraph(
mmt.value,
observableSummary,
isStratified.value && stratifiedView.value === StratifiedView.Collapsed
);
// Render graph, this will either render to the DOM or a virutal element
if (renderer) {
renderer.isGraphDirty = true;
await renderer.setData(graphData);
await renderer.render();
}
// If not interactive, convert elem buffer into image
if (props.featureConfig?.isPreview && graphElement.value) {
const svg = elem?.querySelector('svg') as SVGElement;
// Carry background from container
svg.style.background = '#f9fbfa';
const image = await svgToImage(svg);
graphElement.value.innerHTML = '';
graphElement.value.appendChild(image);
elem = null;
}
}
// eslint-disable-next-line
function makeGraphInteractive(renderer: PetrinetRenderer | NestedPetrinetRenderer) {
renderer.on('node-click', (_eventName, _event, selection) => {
const { id, data } = selection.datum();
if (data.type === NodeType.Transition && data.isStratified) {
Expand Down Expand Up @@ -174,19 +216,6 @@ async function renderGraph() {
const { data } = selection.datum();
if (data.type === NodeType.Transition && data.isStratified) hoveredTransitionId.value = '';
});
// Render graph
const graphData = convertToIGraph(
mmt.value,
observableSummary,
isStratified.value && stratifiedView.value === StratifiedView.Collapsed
);
if (renderer) {
renderer.isGraphDirty = true;
await renderer.setData(graphData);
await renderer.render();
}
}
async function toggleCollapsedView(view: StratifiedView) {
Expand Down
8 changes: 6 additions & 2 deletions packages/client/hmi-client/src/utils/svg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@ export const svgToImage = (svgElement: SVGElement): Promise<HTMLImageElement> =>
const serializer = new XMLSerializer();
// embedExternalStyles(svgElement);

const w = svgElement.clientWidth || parseFloat(svgElement.getAttribute('width') as string);
const h = svgElement.clientHeight || parseFloat(svgElement.getAttribute('height') as string);

const svgString = serializer.serializeToString(svgElement);
const svgBlob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(svgBlob);
const img = new Image(svgElement.clientWidth, svgElement.clientHeight);
const finalImg = new Image(svgElement.clientWidth, svgElement.clientHeight);

const img = new Image(w, h);
const finalImg = new Image(w, h);

return new Promise((resolve, reject) => {
img.addEventListener('load', (e: any) => {
Expand Down

0 comments on commit 79c0dcb

Please sign in to comment.