Skip to content

Commit

Permalink
Merge branch 'main' into fix/shorten-ramp-and-slice
Browse files Browse the repository at this point in the history
  • Loading branch information
ShrimpCryptid authored Aug 22, 2024
2 parents 3652a6b + e4759e7 commit 7775d7e
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 32 deletions.
73 changes: 53 additions & 20 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -1,29 +1,62 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<!-- Google Tag Manager -->
<script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != "dataLayer" ? "&l=" + l : "";
j.async = true;
j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, "script", "dataLayer", "GTM-5J7562WW");
</script>
<!-- End Google Tag Manager -->

<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>AICS 3D Volume Viewer</title>
<style>
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}

html, body, main {
width: 100%;
height: 100%;
}
html,
body,
main {
width: 100%;
height: 100%;
}
</style>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet">

</head>
<body style="margin:0">
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap"
rel="stylesheet"
/>
</head>
<body style="margin: 0">
<!-- Google Tag Manager (noscript) -->
<noscript>
<iframe
src="https://www.googletagmanager.com/ns.html?id=GTM-5J7562WW"
height="0"
width="0"
style="display: none; visibility: hidden"
>
</iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->

<div id="cell-viewer"></div>
</body>
</body>
</html>
30 changes: 23 additions & 7 deletions src/aics-image-viewer/shared/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { CameraState } from "@aics/volume-viewer";

import { ChannelState, ViewerState } from "../components/ViewerStateProvider/types";
import { ViewMode, RenderMode, ImageType } from "./enums";
import { ColorArray } from "./utils/colorRepresentations";
Expand Down Expand Up @@ -93,6 +95,22 @@ export const PRESET_COLOR_MAP = Object.freeze([
},
]);

/** Allows the 3D viewer to apply the default camera settings for the view mode. */
const USE_VIEW_MODE_DEFAULT_CAMERA = undefined;

/**
* Reflects the default camera settings the 3D viewer uses on volume load.
* These SHOULD NOT be changed; otherwise, existing shared links that don't specify the
* camera settings will use the new defaults and may be in unexpected orientations or positions.
*/
export const getDefaultCameraState = (): CameraState => ({
position: [0, 0, 5],
target: [0, 0, 0],
up: [0, 1, 0],
fov: 20,
orthoScale: 0.5,
});

export const getDefaultViewerState = (): ViewerState => ({
viewMode: ViewMode.threeD, // "XY", "XZ", "YZ"
renderMode: RenderMode.volumetric, // "pathtrace", "maxproject"
Expand All @@ -110,13 +128,11 @@ export const getDefaultViewerState = (): ViewerState => ({
region: { x: [0, 1], y: [0, 1], z: [0, 1] },
slice: { x: 0.5, y: 0.5, z: 0.5 },
time: 0,
cameraState: {
position: [0, 0, 5],
target: [0, 0, 0],
up: [0, 1, 0],
fov: 20,
orthoScale: 0.5,
},
// Do not override camera position, target, etc. by default;
// instead, let the viewer apply default camera settings based on the view mode.
// This prevents a bug where the camera's position and view mode are set to
// incompatible states and the viewport becomes blank.
cameraState: USE_VIEW_MODE_DEFAULT_CAMERA,
});

export const getDefaultChannelState = (): ChannelState => ({
Expand Down
36 changes: 34 additions & 2 deletions website/utils/test/url_utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { CameraState } from "@aics/volume-viewer";
import { describe, expect, it } from "@jest/globals";

import {
Expand All @@ -16,11 +17,16 @@ import {
serializeViewerUrlParams,
CONTROL_POINTS_REGEX,
LEGACY_CONTROL_POINTS_REGEX,
serializeCameraState,
} from "../url_utils";
import { ChannelState, ViewerState } from "../../../src/aics-image-viewer/components/ViewerStateProvider/types";
import { ImageType, RenderMode, ViewMode } from "../../../src/aics-image-viewer/shared/enums";
import { ViewerChannelSetting } from "../../../src/aics-image-viewer/shared/utils/viewerChannelSettings";
import { getDefaultChannelState, getDefaultViewerState } from "../../../src/aics-image-viewer/shared/constants";
import {
getDefaultCameraState,
getDefaultChannelState,
getDefaultViewerState,
} from "../../../src/aics-image-viewer/shared/constants";

const defaultSettings: ViewerChannelSetting = {
match: 0,
Expand Down Expand Up @@ -390,7 +396,7 @@ describe("Channel state serialization", () => {
});
});

describe("Viewer state serialization", () => {
describe("Viewer state", () => {
const DEFAULT_VIEWER_STATE: ViewerState = {
viewMode: ViewMode.threeD, // "XY", "XZ", "YZ"
renderMode: RenderMode.volumetric, // "pathtrace", "maxproject"
Expand Down Expand Up @@ -540,6 +546,32 @@ describe("Viewer state serialization", () => {
});
});

describe("Camera state", () => {
it("uses default camera state when choosing elements to exclude/ignore", () => {
let cameraState: CameraState = {
...getDefaultCameraState(),
};
// No changes from default
expect(serializeCameraState(cameraState, true)).toEqual(undefined);

cameraState = { ...cameraState, position: [1, 2, 3] };
expect(serializeCameraState(cameraState, true)).toEqual("pos:1:2:3");
});

it("default camera state has not been changed", () => {
// The default camera state should NOT change unless backwards compatibility
// is added to ensure old links still maintain the same camera orientation;
// otherwise, cameras will appear in the new default orientation unexpectedly.
expect(getDefaultCameraState()).toEqual({
position: [0, 0, 5],
target: [0, 0, 0],
up: [0, 1, 0],
fov: 20,
orthoScale: 0.5,
});
});
});

//// DESERIALIZE STATES ///////////////////////

describe("Channel state deserialization", () => {
Expand Down
13 changes: 10 additions & 3 deletions website/utils/url_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import { PerAxis } from "../../src/aics-image-viewer/shared/types";
import { clamp } from "./math_utils";
import { removeMatchingProperties, removeUndefinedProperties } from "./datatype_utils";
import { isEqual } from "lodash";
import { getDefaultChannelState, getDefaultViewerState } from "../../src/aics-image-viewer/shared/constants";
import {
getDefaultCameraState,
getDefaultChannelState,
getDefaultViewerState,
} from "../../src/aics-image-viewer/shared/constants";

export const ENCODED_COMMA_REGEX = /%2C/g;
export const ENCODED_COLON_REGEX = /%3A/g;
Expand Down Expand Up @@ -591,9 +595,12 @@ function parseCameraState(cameraSettings: string | undefined): Partial<CameraSta
return removeUndefinedProperties(result);
}

function serializeCameraState(cameraState: Partial<CameraState>, removeDefaults: boolean): string | undefined {
export function serializeCameraState(cameraState: Partial<CameraState>, removeDefaults: boolean): string | undefined {
if (removeDefaults) {
cameraState = removeMatchingProperties(cameraState, getDefaultViewerState().cameraState ?? {});
// Note that we use the `getDefaultCameraState()` to get the defaults here,
// instead of `getDefaultViewerState().cameraState`. The latter is undefined, which signals
// that the camera should not be modified for URLs that don't specify it.
cameraState = removeMatchingProperties(cameraState, getDefaultCameraState());
if (Object.keys(cameraState).length === 0) {
return undefined;
}
Expand Down

0 comments on commit 7775d7e

Please sign in to comment.