-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement cell types machine, basic controls, and canvas rendering (#392
) * Add cellTypesMachine.js and event bus * Add cell types controls prototype * Add export and canvas Cell types now exported and can be visualized on a dedicated canvas by color * Implement adding cell mode One can enter and escape the addingCells mode and add multiple cells before exiting * Fix loadMachine to default to empty cell types list Fixes a bug where old project zips, for example, would crash because no cellTypes.json is inside the zip file loaded on the front end * Apply automatic changes --------- Co-authored-by: ykevu <ykevu@users.noreply.github.com>
- Loading branch information
Showing
30 changed files
with
1,246 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
frontend/src/Project/Canvas/ToolCanvas/AddCellTypeCanvas.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Canvas when adding cells to a cell type | ||
|
||
import { useSelector } from '@xstate/react'; | ||
import { useEditCellTypes } from '../../ProjectContext'; | ||
import OutlineCellCanvas from './OutlineCellCanvas'; | ||
|
||
const white = [1, 1, 1, 1]; | ||
|
||
function AddCellTypeCanvas({ setBitmaps }) { | ||
const editCellTypes = useEditCellTypes(); | ||
const cell = useSelector(editCellTypes, (state) => state.context.cell); | ||
|
||
if (!cell) { | ||
return null; | ||
} | ||
|
||
return <OutlineCellCanvas setBitmaps={setBitmaps} cell={cell} color={white} />; | ||
} | ||
|
||
export default AddCellTypeCanvas; |
125 changes: 125 additions & 0 deletions
125
frontend/src/Project/Canvas/ToolCanvas/CellTypeCanvas.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Canvas when visualizing cell types | ||
import { useSelector } from '@xstate/react'; | ||
import { useEffect, useRef } from 'react'; | ||
import { | ||
useAlphaGpu, | ||
useArrays, | ||
useCanvas, | ||
useCellMatrix, | ||
useCellTypes, | ||
useImage, | ||
useLabeled, | ||
useSelectedCell, | ||
} from '../../ProjectContext'; | ||
|
||
function CellTypeCanvas({ setBitmaps }) { | ||
const canvas = useCanvas(); | ||
const width = useSelector(canvas, (state) => state.context.width); | ||
const height = useSelector(canvas, (state) => state.context.height); | ||
|
||
const labeled = useLabeled(); | ||
const feature = useSelector(labeled, (state) => state.context.feature); | ||
|
||
const image = useImage(); | ||
const t = useSelector(image, (state) => state.context.t); | ||
|
||
const arrays = useArrays(); | ||
const labeledArray = useSelector( | ||
arrays, | ||
(state) => state.context.labeled && state.context.labeled[feature][t] | ||
); | ||
|
||
const cell = useSelectedCell(); | ||
|
||
const cellTypes = useCellTypes(); | ||
const colorMap = useSelector(cellTypes, (state) => state.context.colorMap); | ||
|
||
const cellMatrix = useCellMatrix(); | ||
|
||
const gpu = useAlphaGpu(); | ||
const kernelRef = useRef(); | ||
|
||
useEffect(() => { | ||
const kernel = gpu.createKernel( | ||
`function (data, cell, cells, numLabels, numValues, colorMap) { | ||
const x = this.thread.x; | ||
const y = this.constants.h - 1 - this.thread.y; | ||
const value = data[y][x]; | ||
let north = value; | ||
let south = value; | ||
let east = value; | ||
let west = value; | ||
if (x !== 0) { | ||
north = data[y][x - 1]; | ||
} | ||
if (x !== this.constants.w - 1) { | ||
south = data[y][x + 1]; | ||
} | ||
if (y !== 0) { | ||
west = data[y - 1][x]; | ||
} | ||
if (y !== this.constants.h - 1) { | ||
east = data[y + 1][x]; | ||
} | ||
let outlineOpacity = 1; | ||
if (value < numValues) { | ||
for (let i = 0; i < numLabels; i++) { | ||
if (cells[value][i] === 1) { | ||
if (cells[north][i] === 0 || cells[south][i] === 0 || cells[west][i] === 0 || cells[east][i] === 0 | ||
|| north >= numValues || south >= numValues || west >= numValues || east >= numValues) | ||
{ | ||
if (i === cell) { | ||
this.color(1, 1, 1, 1); | ||
} | ||
else { | ||
const [r, g, b, a] = colorMap[i]; | ||
this.color(r, g, b, a); | ||
} | ||
} | ||
else { | ||
if (colorMap[i][3] !== 0) { | ||
const [r, g, b, a] = colorMap[i]; | ||
this.color(r, g, b, 0.3); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}`, | ||
{ | ||
constants: { w: width, h: height }, | ||
output: [width, height], | ||
graphical: true, | ||
dynamicArguments: true, | ||
} | ||
); | ||
kernelRef.current = kernel; | ||
}, [gpu, width, height]); | ||
|
||
useEffect(() => { | ||
const kernel = kernelRef.current; | ||
|
||
if (labeledArray && cellMatrix) { | ||
const numValues = cellMatrix.length; | ||
const numLabels = cellMatrix[0].length; | ||
kernel(labeledArray, cell, cellMatrix, numLabels, numValues, colorMap); | ||
// Rerender the parent canvas | ||
createImageBitmap(kernel.canvas).then((bitmap) => { | ||
setBitmaps((bitmaps) => ({ ...bitmaps, types: bitmap })); | ||
}); | ||
} | ||
}, [labeledArray, cell, cellMatrix, colorMap, setBitmaps, width, height]); | ||
|
||
useEffect( | ||
() => () => | ||
setBitmaps((bitmaps) => { | ||
const { types, ...rest } = bitmaps; | ||
return rest; | ||
}), | ||
[setBitmaps] | ||
); | ||
|
||
return null; | ||
} | ||
|
||
export default CellTypeCanvas; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
33 changes: 33 additions & 0 deletions
33
frontend/src/Project/EditControls/CellTypeControls/CellTypeControls.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// Controls for cell types menu, including button for adding cell type, | ||
// the list of cell types, and an editing prompt when adding cells | ||
|
||
import { Box, FormLabel, Button } from '@mui/material'; | ||
import AddCellTypeLabel from './CellTypeUI/AddCellTypeLabel'; | ||
import CellTypeAccordionList from './CellTypeUI/CellTypeAccordionList'; | ||
import EditingPrompt from './CellTypeUI/EditingPrompt'; | ||
|
||
function CellTypeControls() { | ||
return ( | ||
<Box display='flex' flexDirection='column'> | ||
<FormLabel sx={{ marginBottom: 2 }}> | ||
Cell Type Labels | ||
<Button | ||
variant='contained' | ||
disableElevation | ||
disableRipple | ||
style={{ borderRadius: 100 }} | ||
color='secondary' | ||
sx={{ width: 5, height: 20, top: -1, marginLeft: 1 }} | ||
> | ||
{' '} | ||
Beta | ||
</Button> | ||
</FormLabel> | ||
<AddCellTypeLabel /> | ||
<CellTypeAccordionList /> | ||
<EditingPrompt /> | ||
</Box> | ||
); | ||
} | ||
|
||
export default CellTypeControls; |
60 changes: 60 additions & 0 deletions
60
frontend/src/Project/EditControls/CellTypeControls/CellTypeUI/AddCellTypeLabel.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import AddIcon from '@mui/icons-material/Add'; | ||
import { Box, Button } from '@mui/material'; | ||
import ClickAwayListener from '@mui/material/ClickAwayListener'; | ||
import Popper from '@mui/material/Popper'; | ||
import { useReducer, useRef } from 'react'; | ||
import { TwitterPicker } from 'react-color'; | ||
import { useEditCellTypes } from '../../../ProjectContext'; | ||
|
||
function AddCellTypeLabel() { | ||
const editCellTypesRef = useEditCellTypes(); | ||
|
||
const [open, toggle] = useReducer((v) => !v, false); | ||
const anchorRef = useRef(null); | ||
|
||
const handleChange = (color) => { | ||
editCellTypesRef.send({ type: 'ADD_TYPE', color: color.hex }); | ||
toggle(); | ||
}; | ||
|
||
return ( | ||
<Box sx={{ position: 'relative', boxShadow: 3 }}> | ||
<Button | ||
variant='contained' | ||
startIcon={ | ||
<AddIcon | ||
sx={{ | ||
position: 'relative', | ||
top: -0.3, | ||
left: -5, | ||
}} | ||
/> | ||
} | ||
style={{ borderRadius: 10 }} | ||
sx={{ | ||
position: 'absolute', | ||
m: 1, | ||
my: 0.25, | ||
top: 0, | ||
margin: 'auto', | ||
height: '2.5rem', | ||
width: 300, | ||
fontWeight: 'bold', | ||
fontSize: 14, | ||
}} | ||
onClick={toggle} | ||
ref={anchorRef} | ||
size='large' | ||
> | ||
<div style={{ marginRight: 106 }}>Add Cell Type</div> | ||
</Button> | ||
<Popper open={open} anchorEl={anchorRef.current} placement='bottom'> | ||
<ClickAwayListener onClickAway={toggle}> | ||
<TwitterPicker onChange={handleChange} /> | ||
</ClickAwayListener> | ||
</Popper> | ||
</Box> | ||
); | ||
} | ||
|
||
export default AddCellTypeLabel; |
Oops, something went wrong.