// jshint esversion: 6 import { connect } from "react-redux"; import React from "react"; import { Button, InputGroup, Menu, MenuItem, Popover, Position, Icon, PopoverInteractionKind } from "@blueprintjs/core"; import Occupancy from "./occupancy"; import * as globals from "../../globals"; import styles from "./categorical.css"; @connect(state => ({ categoricalSelection: state.categoricalSelection, annotations: state.annotations, colorScale: state.colors.scale, colorAccessor: state.colors.colorAccessor, schema: state.world?.schema, world: state.world })) class CategoryValue extends React.Component { constructor(props) { super(props); this.state = { editedLabelText: "" }; } handleDeleteValue = () => { const { dispatch, metadataField, categoryIndex, categoricalSelection } = this.props; const category = categoricalSelection[metadataField]; const label = category.categoryValues[categoryIndex]; dispatch({ type: "annotation: delete label", metadataField, label }); }; handleAddCurrentSelectionToThisLabel = () => { const { dispatch, metadataField, categoryIndex, categoricalSelection } = this.props; const category = categoricalSelection[metadataField]; const label = category.categoryValues[categoryIndex]; dispatch({ type: "annotation: label current cell selection", metadataField, categoryIndex, label }); }; handleEditValue = () => { const { dispatch, metadataField, categoryIndex, categoricalSelection } = this.props; const { editedLabelText } = this.state; const category = categoricalSelection[metadataField]; const label = category.categoryValues[categoryIndex]; dispatch({ type: "annotation: label edited", editedLabel: editedLabelText, metadataField, categoryIndex, label }); this.setState({ editedLabelText: "" }); }; activateEditLabelMode = () => { const { dispatch, metadataField, categoryIndex } = this.props; dispatch({ type: "annotation: activate edit label mode", metadataField, categoryIndex }); }; cancelEdit = () => { const { dispatch, metadataField, categoryIndex } = this.props; dispatch({ type: "annotation: cancel edit label mode", metadataField, categoryIndex }); }; toggleOff = () => { const { dispatch, metadataField, categoryIndex } = this.props; dispatch({ type: "categorical metadata filter deselect", metadataField, categoryIndex }); }; shouldComponentUpdate = nextProps => { /* Checks to see if at least one of the following changed: * world state * the color accessor (what is currently being colored by) * if this catagorical value's selection status has changed If and only if true, update the component */ const { props } = this; const { metadataField, categoryIndex, categoricalSelection } = props; const { categoricalSelection: newCategoricalSelection } = nextProps; const valueSelectionChange = categoricalSelection[metadataField].categoryValueSelected[ categoryIndex ] !== newCategoricalSelection[metadataField].categoryValueSelected[ categoryIndex ]; const worldChange = props.world !== nextProps.world; const colorAccessorChange = props.colorAccessor !== nextProps.colorAccessor; const annotationsChange = props.annotations !== nextProps.annotations; return ( valueSelectionChange || worldChange || colorAccessorChange || annotationsChange ); }; toggleOn = () => { const { dispatch, metadataField, categoryIndex } = this.props; dispatch({ type: "categorical metadata filter select", metadataField, categoryIndex }); }; handleMouseEnter = () => { const { dispatch, metadataField, categoryIndex } = this.props; dispatch({ type: "category value mouse hover start", metadataField, categoryIndex }); }; handleMouseExit = () => { const { dispatch, metadataField, categoryIndex } = this.props; dispatch({ type: "category value mouse hover end", metadataField, categoryIndex }); }; render() { const { categoricalSelection, metadataField, categoryIndex, colorAccessor, colorScale, i, schema, isUserAnno, annotations } = this.props; if (!categoricalSelection) return null; const category = categoricalSelection[metadataField]; const selected = category.categoryValueSelected[categoryIndex]; const count = category.categoryValueCounts[categoryIndex]; const value = category.categoryValues[categoryIndex]; const displayString = String( category.categoryValues[categoryIndex] ).valueOf(); /* this is the color scale, so add swatches below */ const isColorBy = metadataField === colorAccessor; let categories = null; if (isColorBy && schema) { categories = schema.annotations.obsByName[colorAccessor]?.categories; } return (
{annotations.isEditingLabelName && annotations.labelEditable.category === metadataField && annotations.labelEditable.label === categoryIndex ? null : displayString}
{isUserAnno && annotations.isEditingLabelName && annotations.labelEditable.category === metadataField && annotations.labelEditable.label === categoryIndex ? (
{ e.preventDefault(); this.handleEditValue(); }} > { this.editableInput = input; }} small onChange={e => { this.setState({ editedLabelText: e.target.value }); }} defaultValue={displayString} rightElement={
{colorAccessor && !isColorBy && !annotations.isEditingLabelName ? ( ) : null}
{count} {isUserAnno ? ( {displayString !== globals.unassignedCategoryLabel ? ( ) : null} {displayString !== globals.unassignedCategoryLabel ? ( ) : null} } >
); } } export default CategoryValue;