Skip to content

Commit 1ee1f0a

Browse files
authored
Merge pull request #58 from CarnegieLearningWeb/Tali-Dev
Enable TSV support and fix SVG graph issues
2 parents df1d9af + 0273068 commit 1ee1f0a

4 files changed

Lines changed: 169 additions & 100 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"@types/lodash": "^4.17.1",
3333
"@types/papaparse": "^5.3.14",
3434
"@types/timsort": "^0.3.3",
35-
"caniuse-lite": "^1.0.30001688",
35+
"caniuse-lite": "^1.0.30001699",
3636
"class-variance-authority": "^0.7.0",
3737
"clsx": "^2.1.1",
3838
"d3": "^7.9.0",

src/components/GraphvizParent.tsx

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// React component code
2-
import {FC, RefObject, useContext, useEffect, useRef, useState} from 'react';
3-
import {graphviz} from 'd3-graphviz';
2+
import React, { FC, RefObject, useContext, useEffect, useRef, useState } from 'react';
3+
import { graphviz } from 'd3-graphviz';
44
import {
55
generateDotString,
66
normalizeThicknesses,
@@ -11,8 +11,8 @@ import {
1111
} from './GraphvizProcessing';
1212
import ErrorBoundary from "@/components/errorBoundary.tsx";
1313
import '../GraphvizContainer.css';
14-
import {Context} from "@/Context.tsx";
15-
import {Button} from './ui/button';
14+
import { Context } from "@/Context.tsx";
15+
import { Button } from './ui/button';
1616

1717
interface GraphvizParentProps {
1818
csvData: string;
@@ -21,11 +21,16 @@ interface GraphvizParentProps {
2121
minVisits: number;
2222
}
2323

24-
const GraphvizParent: FC<GraphvizParentProps> = ({csvData, filter, selfLoops, minVisits}) => {
24+
const GraphvizParent: React.FC<GraphvizParentProps> = ({
25+
csvData,
26+
filter,
27+
selfLoops,
28+
minVisits,
29+
}) => {
2530
const [dotString, setDotString] = useState<string | null>(null);
2631
const [filteredDotString, setFilteredDotString] = useState<string | null>(null);
2732
const [topDotString, setTopDotString] = useState<string | null>(null);
28-
const {selectedSequence, setSelectedSequence, top5Sequences, setTop5Sequences} = useContext(Context);
33+
const { selectedSequence, setSelectedSequence, top5Sequences, setTop5Sequences } = useContext(Context);
2934

3035
// Refs for rendering the Graphviz graphs
3136
const graphRefMain = useRef<HTMLDivElement>(null);
@@ -121,33 +126,8 @@ const GraphvizParent: FC<GraphvizParentProps> = ({csvData, filter, selfLoops, mi
121126
}
122127
}, [csvData, filter, selfLoops, minVisits, selectedSequence]);
123128

124-
// Render Graphviz graphs using d3-graphviz
125-
const renderGraph = (
126-
dot: string | null,
127-
ref: React.RefObject<HTMLDivElement>,
128-
filename: string,
129-
numberOfGraphs: number
130-
) => {
131-
if (dot && ref.current) {
132-
// Dynamically adjust width based on the number of graphs
133-
const width = numberOfGraphs === 3 ? 325 : 425; // Adjust the width for 3 graphs or 2 graphs
134-
const height = 530; // Fixed height (or adjust dynamically if needed)
135-
136-
graphviz(ref.current)
137-
.width(width)
138-
.height(height)
139-
.renderDot(dot)
140-
.on('end', () => {
141-
const svgElement = ref.current?.querySelector('svg');
142-
if (svgElement) {
143-
exportGraphAsPNG(ref, filename);
144-
}
145-
});
146-
}
147-
};
148-
149129
// Export a graph as high-quality PNG
150-
const exportGraphAsPNG = (graphRef: RefObject<HTMLDivElement>, filename: string) => {
130+
const exportGraphAsPNG = (graphRef: React.RefObject<HTMLDivElement>, filename: string) => {
151131
if (!graphRef.current) return;
152132

153133
const svgElement = graphRef.current.querySelector('svg');
@@ -197,17 +177,47 @@ const GraphvizParent: FC<GraphvizParentProps> = ({csvData, filter, selfLoops, mi
197177

198178
const numberOfGraphs = [topDotString, dotString, filteredDotString].filter(Boolean).length;
199179

180+
// Render Graphviz graphs using d3-graphviz
181+
const renderGraph = (
182+
dot: string | null,
183+
ref: React.RefObject<HTMLDivElement>,
184+
filename: string,
185+
numberOfGraphs: number
186+
) => {
187+
if (dot && ref.current) {
188+
// Dynamically adjust width based on the number of graphs
189+
const width = numberOfGraphs === 3 ? 325 : 425;
190+
const height = 530;
191+
192+
try {
193+
graphviz(ref.current)
194+
.width(width)
195+
.height(height)
196+
.renderDot(dot)
197+
} catch (error) {
198+
console.error("Error rendering graph:", error);
199+
}
200+
}
201+
};
202+
203+
200204
useEffect(() => {
201-
renderGraph(filteredDotString, graphRefFiltered, 'filtered_graph', numberOfGraphs);
202-
}, [topDotString]);
205+
if (topDotString && graphRefTop.current) {
206+
renderGraph(topDotString, graphRefTop, 'selected_sequence', numberOfGraphs);
207+
}
208+
}, [topDotString, numberOfGraphs]);
203209

204210
useEffect(() => {
205-
renderGraph(topDotString, graphRefTop, 'selected_sequence', numberOfGraphs);
206-
}, [dotString]);
211+
if (dotString && graphRefMain.current) {
212+
renderGraph(dotString, graphRefMain, 'all_students', numberOfGraphs);
213+
}
214+
}, [dotString, numberOfGraphs]);
207215

208216
useEffect(() => {
209-
renderGraph(dotString, graphRefMain, 'all_students', numberOfGraphs);
210-
}, [filteredDotString]);
217+
if (filteredDotString && graphRefFiltered.current) {
218+
renderGraph(filteredDotString, graphRefFiltered, 'filtered_graph', numberOfGraphs);
219+
}
220+
}, [filteredDotString, numberOfGraphs]);
211221

212222

213223
return (
@@ -219,25 +229,25 @@ const GraphvizParent: FC<GraphvizParentProps> = ({csvData, filter, selfLoops, mi
219229
className={`graph-item flex flex-col items-center ${topDotString && dotString && filteredDotString ? 'w-[400px]' : 'w-[500px]'} border-2 border-gray-700 rounded-lg p-4 bg-gray-100`}>
220230
<h2 className="text-lg font-semibold text-center mb-2">Selected Sequence</h2>
221231
<div ref={graphRefTop}
222-
className="w-full h-[575px] border-2 border-gray-700 rounded-lg p-4 bg-white items-center"></div>
223-
<ExportButton onClick={() => exportGraphAsPNG(graphRefTop, 'selected_sequence')}/>
232+
className="w-full h-[575px] border-2 border-gray-700 rounded-lg p-4 bg-white items-center"></div>
233+
<ExportButton onClick={() => exportGraphAsPNG(graphRefTop, 'selected_sequence')} />
224234
</div>
225235
)}
226236
{dotString && (
227237
<div
228238
className={`graph-item flex flex-col items-center ${topDotString && dotString && filteredDotString ? 'w-[400px]' : 'w-[500px]'} border-2 border-gray-700 rounded-lg p-4 bg-gray-100`}>
229239
<h2 className="text-lg font-semibold text-center mb-2">All Students, All Paths</h2>
230240
<div ref={graphRefMain}
231-
className="w-full h-[575px] border-2 border-gray-700 rounded-lg p-4 bg-white"></div>
232-
<ExportButton onClick={() => exportGraphAsPNG(graphRefMain, 'all_students')}/></div>
241+
className="w-full h-[575px] border-2 border-gray-700 rounded-lg p-4 bg-white"></div>
242+
<ExportButton onClick={() => exportGraphAsPNG(graphRefMain, 'all_students')} /></div>
233243
)}
234244
{filteredDotString && (
235245
<div
236246
className={`graph-item flex flex-col items-center ${topDotString && dotString && filteredDotString ? 'w-[400px]' : 'w-[500px]'} border-2 border-gray-700 rounded-lg p-4 bg-gray-100`}>
237247
<h2 className="text-lg font-semibold text-center mb-4">Filtered Graph</h2>
238248
<div ref={graphRefFiltered}
239-
className="w-full h-[575px] border-2 border-gray-700 rounded-lg p-4 bg-white"></div>
240-
<ExportButton onClick={() => exportGraphAsPNG(graphRefFiltered, 'filtered_graph')}/>
249+
className="w-full h-[575px] border-2 border-gray-700 rounded-lg p-4 bg-white"></div>
250+
<ExportButton onClick={() => exportGraphAsPNG(graphRefFiltered, 'filtered_graph')} />
241251
</div>
242252
)}
243253
</div>
@@ -254,7 +264,7 @@ interface ExportButtonProps {
254264
label?: string;
255265
}
256266

257-
function ExportButton({onClick, label = "Export Image"}: ExportButtonProps) {
267+
function ExportButton({ onClick, label = "Export Image" }: ExportButtonProps) {
258268
return (
259269
<Button
260270
variant={'secondary'}
@@ -263,4 +273,4 @@ function ExportButton({onClick, label = "Export Image"}: ExportButtonProps) {
263273
{label}
264274
</Button>
265275
);
266-
};
276+
}

0 commit comments

Comments
 (0)