-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(components): create new LabwareStackRender component (#15842)
# Overview According to new modal designs for labware/adapter/module stacks on desktop and ODD, we need to render an isometric view of each element of the stack, maintaining the topography of each stacked element. The isometric views are constructed by transforming and aligning the labware SVG (top face) along with two new rects (front and left side). All three are scaled, skewed, and rotated at 30˚ angles or its derivatives ([reference](http://jeroenhoek.nl/articles/svg-and-isometric-projection.html)). The "bottom" labware definition is an optional prop, so we have an affordance for rendering an isometric view of a single labware from the same component. The user can choose to highlight both or none of the labware in the stack, resulting in a fill of blue30. In addition, adapters are handled in the following way: - If the adapter is used as the top definition and there is no bottom definition, we render the non-transformed `LabwareAdapter` svg - if the adapter is used as the bottom definition, we render the isometric transform of the well-less adapter face. _**NOTE**_ In this PR, the adapter's height is maintained, but we may also consider setting the height for a bottom adapter as a constant, rendering a standard-height rectangular prism with well-less face. Closes [PLAT-374](https://opentrons.atlassian.net/browse/PLAT-374), [PLAT-377](https://opentrons.atlassian.net/browse/PLAT-377), [PLAT-394](https://opentrons.atlassian.net/browse/PLAT-394), [PLAT-375](https://opentrons.atlassian.net/browse/PLAT-375)
- Loading branch information
Showing
5 changed files
with
212 additions
and
6 deletions.
There are no files selected for viewing
188 changes: 188 additions & 0 deletions
188
components/src/hardware-sim/Labware/LabwareStackRender.tsx
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,188 @@ | ||
import * as React from 'react' | ||
import { WellLabels, StaticLabware } from './labwareInternals' | ||
import { LabwareAdapter } from './LabwareAdapter' | ||
import { COLORS } from '../../helix-design-system' | ||
|
||
import type { LabwareDefinition2 } from '@opentrons/shared-data' | ||
import type { HighlightedWellLabels } from './labwareInternals/types' | ||
import type { LabwareAdapterLoadName } from './LabwareAdapter' | ||
import type { WellLabelOption } from '../..' | ||
|
||
const HIGHLIGHT_COLOR = COLORS.blue30 | ||
const STROKE_WIDTH = 1 | ||
const SKEW_ANGLE_DEGREES = 30 | ||
const SKEW_ANGLE_RADIANS = (SKEW_ANGLE_DEGREES * Math.PI) / 180 | ||
const COSINE_SKEW_ANGLE = Math.cos(SKEW_ANGLE_RADIANS) | ||
|
||
export interface LabwareStackRenderProps { | ||
/** Labware definitions in stack to render */ | ||
definitionTop: LabwareDefinition2 | ||
/** option to highlight well labels with specified color */ | ||
highlightedWellLabels?: HighlightedWellLabels | ||
/** highlight top labware */ | ||
highlightTop: boolean | ||
/** highlight bottom labware if it exists */ | ||
highlightBottom: boolean | ||
gRef?: React.RefObject<SVGGElement> | ||
definitionBottom?: LabwareDefinition2 | ||
shouldRotateAdapterOrientation?: boolean | ||
/** option to show well labels inside or outside of labware outline */ | ||
wellLabelOption?: WellLabelOption | ||
} | ||
|
||
export const LabwareStackRender = ( | ||
props: LabwareStackRenderProps | ||
): JSX.Element => { | ||
const { | ||
gRef, | ||
definitionTop, | ||
definitionBottom, | ||
highlightTop, | ||
wellLabelOption, | ||
shouldRotateAdapterOrientation, | ||
highlightBottom = false, | ||
} = props | ||
|
||
const labwareLoadNameTop = definitionTop.parameters.loadName | ||
const fillColorTop = highlightTop ? HIGHLIGHT_COLOR : COLORS.white | ||
const fillColorBottom = highlightBottom ? HIGHLIGHT_COLOR : COLORS.white | ||
|
||
// only one labware (top) | ||
if (definitionBottom == null) { | ||
const { xDimension, yDimension } = definitionTop.dimensions | ||
const isTopAdapter = definitionTop.metadata.displayCategory === 'adapter' | ||
|
||
return isTopAdapter ? ( | ||
// adapter render | ||
<g | ||
transform={ | ||
shouldRotateAdapterOrientation | ||
? `rotate(180, ${xDimension / 2}, ${yDimension / 2})` | ||
: 'rotate(0, 0, 0)' | ||
} | ||
> | ||
<g> | ||
<LabwareAdapter | ||
labwareLoadName={labwareLoadNameTop as LabwareAdapterLoadName} | ||
/> | ||
</g> | ||
</g> | ||
) : ( | ||
// isometric view of labware | ||
<svg> | ||
<g | ||
transform={`translate(55, 28) rotate(SKEW_ANGLE_DEGREES) skewX(-${SKEW_ANGLE_DEGREES}) scale(${COSINE_SKEW_ANGLE}, ${COSINE_SKEW_ANGLE})`} | ||
ref={gRef} | ||
> | ||
<StaticLabware definition={definitionTop} fill={fillColorBottom} /> | ||
{wellLabelOption != null ? ( | ||
<WellLabels | ||
definition={definitionTop} | ||
wellLabelOption={wellLabelOption} | ||
wellLabelColor={fillColorBottom} | ||
highlightedWellLabels={props.highlightedWellLabels} | ||
/> | ||
) : null} | ||
</g> | ||
<rect | ||
width={definitionTop.dimensions.yDimension - STROKE_WIDTH} | ||
height={definitionTop.dimensions.zDimension - STROKE_WIDTH} | ||
transform={`translate(55, 28) rotate(180) skewY(-${SKEW_ANGLE_DEGREES}) scale(${COSINE_SKEW_ANGLE}, ${COSINE_SKEW_ANGLE})`} | ||
strokeWidth={STROKE_WIDTH} | ||
stroke={COLORS.black90} | ||
fill={fillColorTop} | ||
/> | ||
<rect | ||
width={definitionTop.dimensions.xDimension - STROKE_WIDTH} | ||
height={definitionTop.dimensions.zDimension - STROKE_WIDTH} | ||
transform={`translate(55, 28) skewY(${SKEW_ANGLE_DEGREES}) scale(${ | ||
COSINE_SKEW_ANGLE * 0.5 | ||
}, -${COSINE_SKEW_ANGLE}) `} | ||
strokeWidth={STROKE_WIDTH} | ||
stroke={COLORS.black90} | ||
fill={fillColorTop} | ||
/> | ||
</svg> | ||
) | ||
} | ||
|
||
return ( | ||
<svg> | ||
{/* bottom labware/adapter */} | ||
<g | ||
transform={`translate(55, ${ | ||
28 - definitionTop.dimensions.zDimension * 0.5 - 10 | ||
}) rotate(${SKEW_ANGLE_DEGREES}) skewX(-${SKEW_ANGLE_DEGREES}) scale(${COSINE_SKEW_ANGLE}, ${COSINE_SKEW_ANGLE})`} | ||
ref={gRef} | ||
fill={fillColorBottom} | ||
> | ||
<StaticLabware definition={definitionTop} fill={fillColorBottom} /> | ||
{wellLabelOption != null && | ||
definitionTop.metadata.displayCategory !== 'adapter' ? ( | ||
<WellLabels | ||
definition={definitionTop} | ||
wellLabelOption={wellLabelOption} | ||
wellLabelColor={fillColorBottom} | ||
highlightedWellLabels={props.highlightedWellLabels} | ||
/> | ||
) : null} | ||
</g> | ||
<rect | ||
width={definitionTop.dimensions.yDimension - STROKE_WIDTH} | ||
height={definitionTop.dimensions.zDimension - STROKE_WIDTH} | ||
transform={`translate(55, ${ | ||
28 - definitionTop.dimensions.zDimension * 0.5 - 10 | ||
}) rotate(180) skewY(-${SKEW_ANGLE_DEGREES}) scale(${COSINE_SKEW_ANGLE}, ${COSINE_SKEW_ANGLE})`} | ||
strokeWidth={STROKE_WIDTH} | ||
stroke={COLORS.black90} | ||
fill={fillColorBottom} | ||
/> | ||
<rect | ||
width={definitionTop.dimensions.xDimension - STROKE_WIDTH} | ||
height={definitionTop.dimensions.zDimension - STROKE_WIDTH} | ||
transform={`translate(55, ${ | ||
28 - definitionTop.dimensions.zDimension * 0.5 - 10 | ||
}) skewY(${SKEW_ANGLE_DEGREES}) scale(${ | ||
COSINE_SKEW_ANGLE * 0.5 | ||
}, -${COSINE_SKEW_ANGLE}) `} | ||
strokeWidth={STROKE_WIDTH} | ||
stroke={COLORS.black90} | ||
fill={fillColorBottom} | ||
/> | ||
{/* top labware/adapter */} | ||
<g | ||
transform={`translate(55, 28) rotate(${SKEW_ANGLE_DEGREES}) skewX(-${SKEW_ANGLE_DEGREES}) scale(${COSINE_SKEW_ANGLE}, ${COSINE_SKEW_ANGLE})`} | ||
ref={gRef} | ||
> | ||
<StaticLabware definition={definitionTop} fill={fillColorTop} /> | ||
{wellLabelOption != null && | ||
definitionTop.metadata.displayCategory !== 'adapter' ? ( | ||
<WellLabels | ||
definition={definitionTop} | ||
wellLabelOption={wellLabelOption} | ||
wellLabelColor={fillColorTop} | ||
highlightedWellLabels={props.highlightedWellLabels} | ||
/> | ||
) : null} | ||
</g> | ||
<rect | ||
width={definitionTop.dimensions.yDimension - STROKE_WIDTH} | ||
height={definitionTop.dimensions.zDimension - STROKE_WIDTH} | ||
transform={`translate(55, 28) rotate(180) skewY(-${SKEW_ANGLE_DEGREES}) scale(${COSINE_SKEW_ANGLE}, ${COSINE_SKEW_ANGLE})`} | ||
strokeWidth={STROKE_WIDTH} | ||
stroke={COLORS.black90} | ||
fill={fillColorTop} | ||
/> | ||
<rect | ||
width={definitionTop.dimensions.xDimension - STROKE_WIDTH} | ||
height={definitionTop.dimensions.zDimension - STROKE_WIDTH} | ||
transform={`translate(55, 28) skewY(${SKEW_ANGLE_DEGREES}) scale(${ | ||
COSINE_SKEW_ANGLE * 0.5 | ||
}, -${COSINE_SKEW_ANGLE}) `} | ||
strokeWidth={STROKE_WIDTH} | ||
stroke={COLORS.black90} | ||
fill={fillColorTop} | ||
/> | ||
</svg> | ||
) | ||
} |
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 |
---|---|---|
@@ -1,5 +1,6 @@ | ||
export * from './labwareInternals/index' | ||
export * from './LabwareRender' | ||
export * from './LabwareStackRender' | ||
export * from './Labware' | ||
|
||
export * from './labwareInternals/types' |
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
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