yansari's picture
tweak: nicer upload icon and refined footnote (SIGSPATIAL 2025, CMU)
352e523
Raw
History Blame Contribute Delete
4.41 kB
import { useState, useEffect, useCallback, useRef } from 'react';
import type { ExampleImage } from '../types';
import { fetchExamples, exampleImageUrl } from '../api';
interface Props {
onFile: (file: File) => void;
onExample: (name: string, hasCached: boolean) => void;
}
export default function ImageUpload({ onFile, onExample }: Props) {
const [examples, setExamples] = useState<ExampleImage[]>([]);
const [dragOver, setDragOver] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
fetchExamples()
.then(setExamples)
.catch(() => {});
}, []);
const handleDrop = useCallback(
(e: React.DragEvent) => {
e.preventDefault();
setDragOver(false);
const file = e.dataTransfer.files[0];
if (file && file.type === 'image/png') {
onFile(file);
}
},
[onFile],
);
const handleFileSelect = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) onFile(file);
},
[onFile],
);
return (
<div className="upload-container">
<div className="intro">
<h1 className="intro-title">
<span>Tesseract</span> Floorplan Analyzer
</h1>
<p className="intro-abstract">
Tesseract turns an annotated building floor plan into a navigable graph.
It detects text labels, segments rooms and corridors, finds and
classifies doors, and assembles a typed graph of rooms, corridors,
doors, and floor transitions connected by walkable edges. Upload a floor
plan or open an example to watch the pipeline run, explore the graph,
route between any two rooms, and refine the result by hand.
</p>
</div>
<div
className={`dropzone${dragOver ? ' drag-over' : ''}`}
onDragOver={(e) => {
e.preventDefault();
setDragOver(true);
}}
onDragLeave={() => setDragOver(false)}
onDrop={handleDrop}
onClick={() => inputRef.current?.click()}
>
<svg
className="dropzone-icon"
width="52"
height="52"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="1.6"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M14 3v4a1 1 0 0 0 1 1h4" />
<path d="M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2z" />
<path d="M12 17v-6" />
<path d="m9.5 13.5 2.5-2.5 2.5 2.5" />
</svg>
<div className="dropzone-text">
Drop a floorplan PNG here, or click to select
</div>
<div className="dropzone-sub">Maximum file size: 10 MB</div>
<input
ref={inputRef}
type="file"
accept="image/png"
style={{ display: 'none' }}
onChange={handleFileSelect}
/>
</div>
{examples.length > 0 && (
<div className="examples-section">
<h2>Or try an example</h2>
<div className="example-grid">
{examples.map((ex) => (
<div
key={ex.name}
className="example-card"
onClick={() => onExample(ex.name, ex.has_cached_result)}
>
<img
src={exampleImageUrl(ex.name)}
alt={ex.display_name}
loading="lazy"
/>
<div className="example-card-info">
<div className="example-card-name">{ex.display_name}</div>
<div className="example-card-meta">
<span>{ex.size_kb.toFixed(0)} KB</span>
{ex.has_cached_result && (
<span className="cached-badge">Instant</span>
)}
</div>
</div>
</div>
))}
</div>
</div>
)}
<footer className="intro-footer">
The Tesseract paper was published at ACM SIGSPATIAL 2025. Work by
Carnegie Mellon University.{' '}
<a
href="https://dl.acm.org/doi/abs/10.1145/3748636.3762771"
target="_blank"
rel="noopener noreferrer"
>
Read the paper
</a>
</footer>
</div>
);
}