Skip to content

Commit

Permalink
CELE-107 Code changes from review input
Browse files Browse the repository at this point in the history
  • Loading branch information
dvcorreia committed Oct 31, 2024
1 parent 1882a6a commit 62afe21
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 124 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box } from "@mui/material";
import "ol/ol.css";
import { Feature, MapBrowserEvent, Map as OLMap, View } from "ol";
import { Feature, Map as OLMap, View } from "ol";
import ScaleLine from "ol/control/ScaleLine";
import { shiftKeyOnly } from "ol/events/condition";
import { getCenter } from "ol/extent";
Expand All @@ -12,14 +12,16 @@ import { Projection } from "ol/proj";
import { XYZ } from "ol/source";
import VectorSource from "ol/source/Vector";
import { TileGrid } from "ol/tilegrid";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { useGlobalContext } from "../../../contexts/GlobalContext.tsx";
import { SlidingRing } from "../../../helpers/slidingRing";
import { getEMDataURL, getSegmentationURL, ViewerType } from "../../../models/models.ts";
import type { Dataset } from "../../../rest/index.ts";
import SceneControls from "./SceneControls.tsx";
import { hexToRGBArray, isNeuronVisible, neuronFeatureName, neuronsStyle } from "./neuronsMapFeature.ts";
import { Geometry } from "ol/geom";
import { activeNeuronStyle, neuronFeatureName, selectedNeuronStyle } from "./neuronsMapFeature.ts";
import { FeatureLike } from "ol/Feature";
import { Workspace } from "../../../models/workspace.ts";
import { Coordinate } from "ol/coordinate";

const newEMLayer = (dataset: Dataset, slice: number, tilegrid: TileGrid, projection: Projection): TileLayer<XYZ> => {
return new TileLayer({
Expand All @@ -39,11 +41,62 @@ const newSegLayer = (dataset: Dataset, slice: number) => {
url: getSegmentationURL(dataset, slice),
format: new GeoJSON(),
}),
style: neuronsStyle,
zIndex: 1,
});
};

function neuronsStyle(feature: FeatureLike, workspace: Workspace) {
const neuronName = neuronFeatureName(feature);

const visibleNeurons = workspace.getVisibleNeuronsInEM();
const visibleNeuron = visibleNeurons.find((neuron) => neuron === neuronName);
const color = visibleNeuron ? workspace.visibilities[neuronName][ViewerType.EM].color : undefined;

let selectedNeuron = workspace.getViewerSelectedNeurons(ViewerType.EM).find((neuron) => neuron === neuronName);
if (selectedNeuron) {
return selectedNeuronStyle(feature, color);
}

if (visibleNeuron) {
return activeNeuronStyle(feature, color);
}

return null;
}

function isNeuronVisible(neuronId: string, workspace: Workspace): boolean {
const inVisibles = workspace.getVisibleNeuronsInEM().find((n) => n === neuronId);
if (inVisibles) {
return true;
}

return workspace.getViewerSelectedNeurons(ViewerType.EM).find((n) => n === neuronId) != undefined;
}

function onNeuronSelect(position: Coordinate, source: VectorSource<Feature> | undefined, workspace: Workspace) {
const features = source?.getFeaturesAtCoordinate(position);
if (!features || features.length === 0) {
return;
}

const feature = features[0];
const neuronName = neuronFeatureName(feature);

if (!isNeuronVisible(neuronName, workspace)) {
return;
}

const selectedNeurons = workspace.getViewerSelectedNeurons(ViewerType.EM);
const isSelected = selectedNeurons.includes(neuronName);

if (isSelected) {
workspace.removeSelection(neuronName, ViewerType.EM);
return;
}

workspace.addSelection(neuronName, ViewerType.EM);
}

const scale = new ScaleLine({
units: "metric",
});
Expand Down Expand Up @@ -107,103 +160,18 @@ const EMStackViewer = () => {
// }),
// });

// Sets the neuron feature properties for the style in the viewer.
const refreshNeuronProperties = () => {
const layer = currSegLayer.current;
if (!layer) return;

const source = layer.getSource();
if (!source) return;

const visibilities = currentWorkspace.visibilities;
const visibleNeurons = new Set(currentWorkspace.getVisibleNeuronsInEM());
const selectedNeurons = new Set(currentWorkspace.getViewerSelectedNeurons(ViewerType.EM));

const updateNeuronFeatures = () => {
const features = source.getFeatures();
features.forEach((feature) => {
const neuronName = neuronFeatureName(feature);

{
const property = "active";
const shouldBeEnabled = visibleNeurons.has(neuronName);

const currentValue = feature.get(property);
if (currentValue !== shouldBeEnabled) {
feature.set(property, shouldBeEnabled);
}
}

{
const property = "selected";
const shouldBeEnabled = selectedNeurons.has(neuronName);

const currentValue = feature.get(property);
if (currentValue !== shouldBeEnabled) {
feature.set(property, shouldBeEnabled);
}
}

if (visibleNeurons.has(neuronName)) {
const color = visibilities[neuronName][ViewerType.EM].color;
feature.set("color", hexToRGBArray(color));
}
});
};

// features may not have loaded in some cases where this function is called
if (!source.getFeatures().length) {
source.once("featuresloadend", function () {
updateNeuronFeatures();
});
} else {
updateNeuronFeatures();
}
};
const neuronsStyleRef = useRef((feature: FeatureLike) => neuronsStyle(feature, currentWorkspace));
const onNeuronSelectRef = useRef((position) => onNeuronSelect(position, currSegLayer.current?.getSource(), currentWorkspace));

useEffect(() => {
refreshNeuronProperties();
}, [currentWorkspace, segSlice]);

const onSelectNeuron = useCallback(
(feature: Feature<Geometry>) => {
const neuronName = neuronFeatureName(feature);

// should not be able to click on hidden neurons
if (!isNeuronVisible(feature)) return;

const selectedNeurons = currentWorkspace.getViewerSelectedNeurons(ViewerType.EM);
const isSelected = selectedNeurons.includes(neuronName);

if (isSelected) {
currentWorkspace.removeSelection(neuronName, ViewerType.EM);
return;
}

currentWorkspace.addSelection(neuronName, ViewerType.EM);
},
[currentWorkspace],
);

const onClick = useCallback(
(evt: MapBrowserEvent<any>) => {
if (!currSegLayer.current) return;

const features = currSegLayer.current.getSource().getFeaturesAtCoordinate(evt.coordinate);
if (features.length === 0) return;

const feature = features[0];
if (feature) {
onSelectNeuron(feature);
}
},
[onSelectNeuron],
);
if (!currSegLayer.current?.getSource()) {
return;
}

useEffect(() => {
if (!mapRef.current) return;
mapRef.current.on("click", onClick);
}, [onClick]);
neuronsStyleRef.current = (feature: Feature) => neuronsStyle(feature, currentWorkspace);
onNeuronSelectRef.current = (position) => onNeuronSelect(position, currSegLayer.current?.getSource(), currentWorkspace);
currSegLayer.current.changed();
}, [currentWorkspace.getVisibleNeuronsInEM(), currentWorkspace.visibilities, currentWorkspace.getViewerSelectedNeurons(ViewerType.EM), segSlice]);

useEffect(() => {
if (mapRef.current) {
Expand Down Expand Up @@ -251,6 +219,7 @@ const EMStackViewer = () => {
onPush: (slice) => {
const layer = newSegLayer(firstActiveDataset, slice);
layer.setOpacity(0);
layer.setStyle((feature) => neuronsStyleRef.current(feature));
map.addLayer(layer);
return layer;
},
Expand All @@ -267,8 +236,7 @@ const EMStackViewer = () => {
},
});

refreshNeuronProperties();
map.on("click", onClick);
map.on("click", (e) => onNeuronSelectRef.current(e.coordinate));

function handleSliceScroll(e: WheelEvent) {
const scrollUp = e.deltaY < 0;
Expand Down Expand Up @@ -340,8 +308,6 @@ const EMStackViewer = () => {

const minZoomAvailable = view.getMinZoom();
view.setZoom(minZoomAvailable);

refreshNeuronProperties();
};

const onPrint = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
import Feature, { FeatureLike } from "ol/Feature";
import { FeatureLike } from "ol/Feature";
import Fill from "ol/style/Fill";
import Stroke from "ol/style/Stroke";
import Style from "ol/style/Style";
import Text from "ol/style/Text";

export function isNeuronVisible(feature: Feature) {
return feature.get("selected") || feature.get("active");
}

export function neuronsStyle(feature: FeatureLike) {
if (feature.get("selected")) {
return selectedNeuronStyle(feature);
}

if (feature.get("active")) {
return activeNeuronStyle(feature);
}

return null;
}

export function hexToRGBArray(hex: string): [number, number, number] {
hex = hex.replace("#", "");
const r = parseInt(hex.slice(0, 2), 16);
Expand All @@ -29,9 +13,9 @@ export function hexToRGBArray(hex: string): [number, number, number] {
return [r, g, b];
}

export function activeNeuronStyle(feature: FeatureLike): Style {
export function activeNeuronStyle(feature: FeatureLike, color?: string): Style {
const opacity = 0.2;
const [r, g, b] = feature.get("color");
const [r, g, b] = color ? hexToRGBArray(color) : feature.get("color");
const rgbaColor = `rgba(${r}, ${g}, ${b}, ${opacity})`;

return new Style({
Expand All @@ -45,9 +29,9 @@ export function activeNeuronStyle(feature: FeatureLike): Style {
});
}

export function selectedNeuronStyle(feature: FeatureLike): Style {
export function selectedNeuronStyle(feature: FeatureLike, color?: string): Style {
const opacity = 0.5;
const [r, g, b] = feature.get("color");
const [r, g, b] = color ? hexToRGBArray(color) : feature.get("color");
const rgbaColor = `rgba(${r}, ${g}, ${b}, ${opacity})`;

return new Style({
Expand Down

0 comments on commit 62afe21

Please sign in to comment.