Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
- **HDF5 browser — link cycles:** files containing a group linked into itself or into one of its subgroups were browsed down to a hundred phantom levels, or took too long to open. Such links back to a parent group are now skipped; other aliases are still shown at each of their paths.
- **HDF5 browser — large files:** opening an HDF5 file no longer reads every dataset entirely, including those that cannot be imported (e.g. 3D cubes): datasets are described from a small sample, and their data is read only when previewed or imported. Large files open faster and with much less memory.
- **Embedding — message origins:** the JavaScript SDK accepted responses and events from any document loaded in the DataLab-Web iframe, and DataLab-Web sent its events to host windows whatever document they showed. The SDK now only accepts messages from the configured `targetOrigin`, and DataLab-Web sends its responses and events to the origin from which each host window made its requests.
- **Image viewer — pixel positions:** images were drawn half a pixel off their coordinates: the first pixel started at the image origin instead of being centered on it, as in Sigima and DataLab desktop. Regions of interest, analysis results, the profile crosshair and the statistics rectangle therefore appeared shifted by half a pixel relative to the computed pixels, and the value shown when hovering the image could be that of the neighbouring pixel. Each pixel is now centered on its coordinates in the image viewer, the multi-image views and the processing preview, so overlays, read-outs, cross-sections and statistics match the computations exactly. The default regions of interest and areas to erase are centered on the image, and the preview of _Create ROI grid…_ now shows the same whole-pixel cells as the created regions of interest. Cross-sections and statistics also work on images with non-uniform coordinates.

### Changed

Expand Down
80 changes: 38 additions & 42 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ import {
writeBytesToHandle,
} from "./utils/saveFile";
import { formatBytes } from "./utils/memory";
import { imageCenter, imageExtent } from "./utils/pixelCenters";
import { listRecent } from "./storage/recentStore";
import type {
AnalysisResult,
Expand Down Expand Up @@ -256,6 +257,39 @@ interface PendingPlotResults {
createdIds: string[];
}

/** Default image rectangle (new ROI or area to erase): a quarter of the
* image extent, centered on its pixel grid. */
function defaultImageRectangle(img: ImageData): ImageRoiSegment {
const { xMin, xMax, yMin, yMax } = imageExtent(img);
const center = imageCenter(img);
const sx = (xMax - xMin) / 4 || 1;
const sy = (yMax - yMin) / 4 || 1;
return {
geometry: "rectangle",
title: "",
inverse: false,
x0: center.x - sx / 2,
y0: center.y - sy / 2,
dx: sx,
dy: sy,
};
}

/** Default image circle ROI, centered on the pixel grid of the image. */
function defaultImageCircle(img: ImageData): ImageRoiSegment {
const { xMin, xMax, yMin, yMax } = imageExtent(img);
const center = imageCenter(img);
const r = Math.min(xMax - xMin, yMax - yMin) / 4 || 1;
return {
geometry: "circle",
title: "",
inverse: false,
xc: center.x,
yc: center.y,
r,
};
}

/** Build the (hand-made, fully localised) DataSet schema for one
* "Plot results" category dialog. Mirrors DataLab desktop's
* ``__create_plot_result_param_class``: a plot-kind choice plus X / Y
Expand Down Expand Up @@ -3143,21 +3177,9 @@ export default function App() {

const handleImageAddRectangle = useCallback(async () => {
if (!runtime || !currentId || !imageData) return;
const sx = (imageData.width * imageData.dx) / 4 || 1;
const sy = (imageData.height * imageData.dy) / 4 || 1;
const x0 = imageData.x0 + (imageData.width * imageData.dx) / 2 - sx / 2;
const y0 = imageData.y0 + (imageData.height * imageData.dy) / 2 - sy / 2;
const next: ImageRoiSegment[] = [
...imageRoi,
{
geometry: "rectangle",
title: "",
inverse: false,
x0,
y0,
dx: sx,
dy: sy,
},
defaultImageRectangle(imageData),
];
setImageRoi(next);
setRoiDrawGeometry(null);
Expand All @@ -3168,16 +3190,9 @@ export default function App() {

const handleImageAddCircle = useCallback(async () => {
if (!runtime || !currentId || !imageData) return;
const r =
Math.min(
imageData.width * imageData.dx,
imageData.height * imageData.dy,
) / 4 || 1;
const xc = imageData.x0 + (imageData.width * imageData.dx) / 2;
const yc = imageData.y0 + (imageData.height * imageData.dy) / 2;
const next: ImageRoiSegment[] = [
...imageRoi,
{ geometry: "circle", title: "", inverse: false, xc, yc, r },
defaultImageCircle(imageData),
];
setImageRoi(next);
setRoiDrawGeometry(null);
Expand Down Expand Up @@ -3375,21 +3390,7 @@ export default function App() {
* Mirrors DataLab desktop's ``compute_erase``. */
const handleOpenErase = useCallback(() => {
if (!runtime || !currentId || !imageData) return;
const sx = (imageData.width * imageData.dx) / 4 || 1;
const sy = (imageData.height * imageData.dy) / 4 || 1;
const x0 = imageData.x0 + (imageData.width * imageData.dx) / 2 - sx / 2;
const y0 = imageData.y0 + (imageData.height * imageData.dy) / 2 - sy / 2;
setEraseRegions([
{
geometry: "rectangle",
title: "",
inverse: false,
x0,
y0,
dx: sx,
dy: sy,
},
]);
setEraseRegions([defaultImageRectangle(imageData)]);
setSelectedRoiIndex(0);
setActiveRoiVertex(null);
setRoiDrawGeometry("rectangle");
Expand Down Expand Up @@ -5218,12 +5219,7 @@ export default function App() {
imageRoi={imageEraseMode ? eraseRegions : imageRoi}
bounds={
treeKind === "image" && imageData
? {
xMin: imageData.x0,
xMax: imageData.x0 + imageData.width * imageData.dx,
yMin: imageData.y0,
yMax: imageData.y0 + imageData.height * imageData.dy,
}
? imageExtent(imageData)
: {
xMin: data?.x[0] ?? 0,
xMax: data?.x[(data?.x.length ?? 1) - 1] ?? 1,
Expand Down
Loading
Loading