diff --git a/package-lock.json b/package-lock.json
index 149426d0..88b208ac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "0.9.0",
"license": "ISC",
"dependencies": {
- "@aics/simularium-viewer": "^3.6.1",
+ "@aics/simularium-viewer": "^3.6.2",
"@ant-design/css-animation": "^1.7.3",
"@ant-design/icons": "^4.0.6",
"antd": "^4.23.6",
@@ -111,9 +111,9 @@
"dev": true
},
"node_modules/@aics/simularium-viewer": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/@aics/simularium-viewer/-/simularium-viewer-3.6.1.tgz",
- "integrity": "sha512-vP5PsMHc8J3BJg7D2bXz7eeSKom+TSkgs6gr5OKSqcZif4OljOgQEowEZH6MaYLviY+Xpyt1KSO3bg8BB2ExkQ==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/@aics/simularium-viewer/-/simularium-viewer-3.6.2.tgz",
+ "integrity": "sha512-QTuxtExeqFYhAmfr4VFqpu9QKVqd0Vg1znaDFUyV4qGEr9W1hDlA2evxK3c3PXnNn/wNCWEE1SnrWRjSzjesIA==",
"dependencies": {
"@fortawesome/fontawesome-free": "^5.15.2",
"@fortawesome/fontawesome-svg-core": "~1.2.34",
@@ -24354,9 +24354,9 @@
"dev": true
},
"@aics/simularium-viewer": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/@aics/simularium-viewer/-/simularium-viewer-3.6.1.tgz",
- "integrity": "sha512-vP5PsMHc8J3BJg7D2bXz7eeSKom+TSkgs6gr5OKSqcZif4OljOgQEowEZH6MaYLviY+Xpyt1KSO3bg8BB2ExkQ==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/@aics/simularium-viewer/-/simularium-viewer-3.6.2.tgz",
+ "integrity": "sha512-QTuxtExeqFYhAmfr4VFqpu9QKVqd0Vg1znaDFUyV4qGEr9W1hDlA2evxK3c3PXnNn/wNCWEE1SnrWRjSzjesIA==",
"requires": {
"@fortawesome/fontawesome-free": "^5.15.2",
"@fortawesome/fontawesome-svg-core": "~1.2.34",
diff --git a/package.json b/package.json
index 9ed9b5d9..f71e7e5a 100644
--- a/package.json
+++ b/package.json
@@ -92,7 +92,7 @@
"webpack-dev-server": "^4.10.1"
},
"dependencies": {
- "@aics/simularium-viewer": "^3.6.1",
+ "@aics/simularium-viewer": "^3.6.2",
"@ant-design/css-animation": "^1.7.3",
"@ant-design/icons": "^4.0.6",
"antd": "^4.23.6",
diff --git a/src/assets/orthographic.svg b/src/assets/orthographic.svg
new file mode 100644
index 00000000..b2295316
--- /dev/null
+++ b/src/assets/orthographic.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/perspective.svg b/src/assets/perspective.svg
new file mode 100644
index 00000000..558fca8e
--- /dev/null
+++ b/src/assets/perspective.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/components/CameraControls/index.tsx b/src/components/CameraControls/index.tsx
index aed5086f..565a4a65 100644
--- a/src/components/CameraControls/index.tsx
+++ b/src/components/CameraControls/index.tsx
@@ -10,12 +10,21 @@ import styles from "./style.css";
const PAN = "pan";
const ROTATE = "rotate";
+const ORTHOGRAPHIC = "o";
+const PERSPECTIVE = "p";
const CAMERA_MODE_MODIFIER_KEYS = ["Meta", "Shift"];
const ZOOM_IN_HK = "ArrowUp";
const ZOOM_OUT_HK = "ArrowDown";
const RESET_HK = "h";
const FOCUS_HK = "f";
-const HOT_KEYS = [ZOOM_IN_HK, ZOOM_OUT_HK, RESET_HK, FOCUS_HK];
+const HOT_KEYS = [
+ ZOOM_IN_HK,
+ ZOOM_OUT_HK,
+ RESET_HK,
+ FOCUS_HK,
+ ORTHOGRAPHIC,
+ PERSPECTIVE,
+];
interface CameraControlsProps {
resetCamera: () => void;
@@ -23,6 +32,7 @@ interface CameraControlsProps {
zoomOut: () => void;
setPanningMode: (value: boolean) => void;
setFocusMode: (value: boolean) => void;
+ setCameraType: (value: boolean) => void;
}
const CameraControls = ({
@@ -31,9 +41,12 @@ const CameraControls = ({
zoomOut,
setPanningMode,
setFocusMode,
+ setCameraType,
}: CameraControlsProps): JSX.Element => {
const [isFocused, saveFocusMode] = useState(true);
const [mode, setMode] = useState(ROTATE);
+ const [cameraProjectionType, setCameraProjectionType] =
+ useState(PERSPECTIVE);
const [keyPressed, setKeyPressed] = useState("");
const lastKeyPressed = useRef("");
@@ -91,6 +104,10 @@ const CameraControls = ({
}
}, [mode]);
+ useEffect(() => {
+ setCameraType(cameraProjectionType === ORTHOGRAPHIC);
+ }, [cameraProjectionType]);
+
useEffect(() => {
if (
(isModifierKey(keyPressed) && !lastKeyPressed.current) ||
@@ -113,6 +130,12 @@ const CameraControls = ({
case FOCUS_HK:
saveFocusMode(!isFocused);
break;
+ case ORTHOGRAPHIC:
+ setCameraProjectionType(ORTHOGRAPHIC);
+ break;
+ case PERSPECTIVE:
+ setCameraProjectionType(PERSPECTIVE);
+ break;
default:
break;
}
@@ -120,6 +143,30 @@ const CameraControls = ({
}, [keyPressed]);
return (
+
+
+
+
+
+
+
+
-
- saveFocusMode(!isFocused)}
+
+
+
+
+ {/* Should be radio buttons, but using radio buttons
+ detaches keypressed listener after the button is pressed */}
+ {
+ setCameraProjectionType(ORTHOGRAPHIC);
+ }}
+ icon={Icons.OrthographicCamera}
+ >
+
+
-
-
-
+ onClick={() => {
+ setCameraProjectionType(PERSPECTIVE);
+ }}
+ icon={Icons.PerspectiveCamera}
+ >
+
+
-
-
-
-
-
-
+ {
+ saveFocusMode(!isFocused);
+ }}
>
-
-
-
+
+
diff --git a/src/components/CameraControls/style.css b/src/components/CameraControls/style.css
index 4ba5ecdb..672b9c23 100644
--- a/src/components/CameraControls/style.css
+++ b/src/components/CameraControls/style.css
@@ -5,72 +5,74 @@
bottom: 0;
right: 20px;
justify-content: space-evenly;
+ gap: 12px;
margin-bottom: 20px;
}
+.container :global(.ant-btn) {
+ height: 26px;
+ width: 26px;
+ background-color: var(--viewer-btn-bg-default);
+}
+
.radio-group {
display: flex;
flex-flow: column;
+ justify-content: space-evenly;
}
+
.zoom-buttons {
display: flex;
flex-direction: column;
justify-content: space-evenly;
height: 60px;
- margin-bottom: 4px;
-
-}
-
-.move-buttons {
- display: flex;
- height: 84px;
- flex-flow: column;
- justify-content: space-evenly;
}
.btn {
- background-color: var(--dark-theme-btn-bg);
- color: var(--dark-theme-btn-color);
+ background-color: var(--viewer-btn-bg-default);
+ color: var(--viewer-btn-color-default);
border-radius: 3px!important;
+ height: 26px !important;
+ width: 26px !important;
}
.radio-btn {
- border-color: var(--dark-theme-btn-bg)!important;
- background-color: black!important;
padding: 0 2px!important;
- width: 24px;
- height: 24px;
+ width: 26px;
+ height: 26px;
font-size: 18px;
line-height: 18px;
border-left-width: 1px;
+ border: none;
}
-.radio-group .radio-btn:first-child {
- border-radius: 3px 3px 0px 0px;
+.radio-btn.active {
+ color: var(--viewer-btn-color-default) !important;
+ background-color: var(--viewer-btn-bg-default) !important;
+ border: 1px solid var(--viewer-btn-border-active) !important;
}
-.radio-group .radio-btn:last-child {
- border-radius: 0px 0px 3px 3px;
-}
-
-.radio-btn.active {
- color: var(--dark-theme-btn-color) !important;
- background-color: var(--dark-theme-btn-bg) !important;
+.radio-btn:hover {
+ color: var(--viewer-btn-color-default);
+ background-color: var(--viewer-btn-bg-hover)!important;
}
.radio-group .radio-btn:not(:first-child) {
border-top: 0px;
}
-.radio-btn:hover {
- color: var(--dark-theme-btn-color);
- background-color: var(--dark-theme-btn-hover-bg)!important;
+.radio-group .radio-btn:first-child {
+ border-radius: 3px 3px 0px 0px;
}
-.btn:hover,
-.btn:active {
- color: var(--dark-theme-btn-color);
- background-color: var(--dark-theme-btn-hover-bg);
+.radio-group .radio-btn:last-child {
+ border-radius: 0px 0px 3px 3px;
+}
+
+.btn:hover {
+ color: var(--viewer-btn-color-default);
+ background-color: var(--viewer-btn-bg-hover);
+ border: 1px solid var(--viewer-btn-border-active) !important;
}
.btn:focus {
@@ -78,12 +80,23 @@
color: var(--dark-theme-btn-color);
}
+.btn:hover:focus {
+ color: var(--viewer-btn-color-default);
+ background-color: var(--viewer-btn-bg-hover);
+}
+
.btn[disabled] {
- background-color: var(--dark-theme-btn-disabled-bg);
- color: var(--dark-theme-btn-disabled-color);
+ background-color: var(--viewer-btn-bg-disabled);
+ color: var(--viewer-btn-color-disabled);
}
+.container .anticon svg {
+ height: 24px;
+ width: 24px;
+ color: var(--viewer-btn-color-default);
+}
+
.rotate::after {
content: "\e909";
}
diff --git a/src/components/Icons/index.tsx b/src/components/Icons/index.tsx
index ffa98b7a..2d9fcf62 100644
--- a/src/components/Icons/index.tsx
+++ b/src/components/Icons/index.tsx
@@ -21,6 +21,8 @@ import AicsLogoWhite from "../../assets/AICS-logo-full.png";
import ClockwiseArrow from "../../assets/step-forward.svg";
import CounterClockwiseArrow from "../../assets/step-back.svg";
import Beta from "../../assets/beta.svg";
+import Orthographic from "../../assets/orthographic.svg";
+import Perspective from "../../assets/perspective.svg";
export const Loading = ;
export const Play = ;
@@ -43,6 +45,8 @@ export const AicsLogo = ;
export const StepForward = ;
export const StepBack = ;
export const BetaTag = ;
+export const OrthographicCamera = ;
+export const PerspectiveCamera = ;
export default {
StepBack,
@@ -66,4 +70,6 @@ export default {
Link,
Download,
LoopOutlined,
+ OrthographicCamera,
+ PerspectiveCamera,
};
diff --git a/src/components/PlaybackControls/index.tsx b/src/components/PlaybackControls/index.tsx
index 7643a7e5..5100eafc 100644
--- a/src/components/PlaybackControls/index.tsx
+++ b/src/components/PlaybackControls/index.tsx
@@ -129,7 +129,6 @@ const PlayBackControls = ({
btnClassNames,
{ [styles.customStepButton]: !loading },
])}
- size="small"
onClick={prevHandler}
disabled={isStepBackDisabled || loading || isEmpty}
loading={loading}
@@ -152,8 +151,10 @@ const PlayBackControls = ({
color={TOOLTIP_COLOR}
>
playHandler()}
loading={loading}
@@ -170,7 +171,6 @@ const PlayBackControls = ({
btnClassNames,
{ [styles.customStepButton]: !loading },
])}
- size="small"
onClick={nextHandler}
disabled={isStepForwardDisabled || loading || isEmpty}
loading={loading}
@@ -221,16 +221,10 @@ const PlayBackControls = ({
arrowPointAtCenter
>
{
zoomOut={simulariumController.zoomOut}
setPanningMode={simulariumController.setPanningMode}
setFocusMode={simulariumController.setFocusMode}
+ setCameraType={simulariumController.setCameraType}
/>
);
diff --git a/src/styles/colors.css b/src/styles/colors.css
index 25c6b10a..2b89c049 100644
--- a/src/styles/colors.css
+++ b/src/styles/colors.css
@@ -13,10 +13,12 @@
--white-six: #e7e7e7;
--transparent-white: rgba(255, 255, 255, 0.65);
--dim-gray: #383838;
+ --dim-gray-two: #6E6E6E;
+ --purplish-gray: #4A4658;
--pale-grey: #ddd9ec;
--heather: #bab5c9;
--text-gray: #a0a0a0;
- --greyish-brown: #4a4a4a;
+ --grayish-brown: #4a4a4a;
--warm-gray: #979797;
--charcoal-grey: #3b3649;
--dark-blue-grey: #2d224d;
@@ -72,4 +74,11 @@
--light-theme-modal-supplemental-text: var(--charcoal-grey);
--light-theme-modal-btn-default-color: var(--dark-four);
--light-theme-btn-default-disabled-bg: var(--heather);
+ --viewer-btn-bg-default: var(--dark-three);
+ --viewer-btn-bg-hover: var(--purplish-gray);
+ --viewer-btn-bg-disabled: var(--dark-three);
+ --viewer-btn-border-active: var( --white-three);
+ --viewer-btn-border-on: var(--dim-gray-two);
+ --viewer-btn-color-default: var(--white-three);
+ --viewer-btn-color-disabled: var(--grayish-brown);
}