mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-23 10:38:11 +08:00
run prettier(2.0.5) (#1438)
This commit is contained in:
@@ -14,10 +14,10 @@ import TermsOfServicePrompt from "./termsPrompt";
|
||||
|
||||
import actions from "../actions";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
loading: state.controls.loading,
|
||||
error: state.controls.error,
|
||||
graphRenderCounter: state.controls.graphRenderCounter
|
||||
graphRenderCounter: state.controls.graphRenderCounter,
|
||||
}))
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -40,16 +40,16 @@ class App extends React.Component {
|
||||
type: "window resize",
|
||||
data: {
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth
|
||||
}
|
||||
width: window.innerWidth,
|
||||
},
|
||||
});
|
||||
});
|
||||
dispatch({
|
||||
type: "window resize",
|
||||
data: {
|
||||
height: window.innerHeight,
|
||||
width: window.innerWidth
|
||||
}
|
||||
width: window.innerWidth,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class App extends React.Component {
|
||||
position: "fixed",
|
||||
fontWeight: 500,
|
||||
top: window.innerHeight / 2,
|
||||
left: window.innerWidth / 2 - 50
|
||||
left: window.innerWidth / 2 - 50,
|
||||
}}
|
||||
>
|
||||
loading cellxgene
|
||||
@@ -82,7 +82,7 @@ class App extends React.Component {
|
||||
position: "fixed",
|
||||
fontWeight: 500,
|
||||
top: window.innerHeight / 2,
|
||||
left: window.innerWidth / 2 - 50
|
||||
left: window.innerWidth / 2 - 50,
|
||||
}}
|
||||
>
|
||||
error loading
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
InputGroup,
|
||||
Dialog,
|
||||
Classes,
|
||||
Colors
|
||||
Colors,
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
universe: state.universe,
|
||||
idhash: state.config?.parameters?.["annotations-user-data-idhash"] ?? null,
|
||||
annotations: state.annotations,
|
||||
@@ -18,13 +18,13 @@ import {
|
||||
saveInProgress: state.autosave?.saveInProgress ?? false,
|
||||
lastSavedObsAnnotations: state.autosave?.lastSavedObsAnnotations,
|
||||
error: state.autosave?.error,
|
||||
writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false
|
||||
writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false,
|
||||
}))
|
||||
class FilenameDialog extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
filenameText: ""
|
||||
filenameText: "",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class FilenameDialog extends React.Component {
|
||||
|
||||
dispatch({
|
||||
type: "set annotations collection name",
|
||||
data: filenameText
|
||||
data: filenameText,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -71,7 +71,7 @@ class FilenameDialog extends React.Component {
|
||||
fontStyle: "italic",
|
||||
fontSize: 12,
|
||||
marginTop: 5,
|
||||
color: Colors.ORANGE3
|
||||
color: Colors.ORANGE3,
|
||||
}}
|
||||
>
|
||||
Name cannot be blank
|
||||
@@ -84,7 +84,7 @@ class FilenameDialog extends React.Component {
|
||||
fontStyle: "italic",
|
||||
fontSize: 12,
|
||||
marginTop: 5,
|
||||
color: Colors.ORANGE3
|
||||
color: Colors.ORANGE3,
|
||||
}}
|
||||
>
|
||||
Only alphanumeric and underscore allowed
|
||||
@@ -108,7 +108,7 @@ class FilenameDialog extends React.Component {
|
||||
onClose={this.dismissFilenameDialog}
|
||||
>
|
||||
<form
|
||||
onSubmit={e => {
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
this.handleCreateFilename();
|
||||
}}
|
||||
@@ -120,7 +120,9 @@ class FilenameDialog extends React.Component {
|
||||
autoFocus
|
||||
value={filenameText}
|
||||
intent={this.filenameError(filenameText) ? "warning" : "none"}
|
||||
onChange={e => this.setState({ filenameText: e.target.value })}
|
||||
onChange={(e) =>
|
||||
this.setState({ filenameText: e.target.value })
|
||||
}
|
||||
leftIcon="tag"
|
||||
/>
|
||||
<p
|
||||
@@ -129,7 +131,7 @@ class FilenameDialog extends React.Component {
|
||||
visibility: this.filenameError(filenameText)
|
||||
? "visible"
|
||||
: "hidden",
|
||||
color: Colors.ORANGE3
|
||||
color: Colors.ORANGE3,
|
||||
}}
|
||||
>
|
||||
{this.filenameErrorMessage(filenameText)}
|
||||
|
||||
@@ -4,7 +4,7 @@ import * as globals from "../../globals";
|
||||
import actions from "../../actions";
|
||||
import FilenameDialog from "./filenameDialog";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
universe: state.universe,
|
||||
annotations: state.annotations,
|
||||
obsAnnotations: state.universe.obsAnnotations,
|
||||
@@ -12,13 +12,13 @@ import FilenameDialog from "./filenameDialog";
|
||||
lastSavedObsAnnotations: state.autosave?.lastSavedObsAnnotations,
|
||||
error: state.autosave?.error,
|
||||
writableCategoriesEnabled: state.config?.parameters?.["annotations"] ?? false,
|
||||
initialDataLoadComplete: state.autosave?.initialDataLoadComplete
|
||||
initialDataLoadComplete: state.autosave?.initialDataLoadComplete,
|
||||
}))
|
||||
class Autosave extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
timer: null
|
||||
timer: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -64,22 +64,26 @@ class Autosave extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { writableCategoriesEnabled, saveInProgress, initialDataLoadComplete } = this.props;
|
||||
const {
|
||||
writableCategoriesEnabled,
|
||||
saveInProgress,
|
||||
initialDataLoadComplete,
|
||||
} = this.props;
|
||||
return writableCategoriesEnabled ? (
|
||||
<div
|
||||
id="autosave"
|
||||
data-testclass={
|
||||
!initialDataLoadComplete
|
||||
? "autosave-init"
|
||||
: (this.needToSave() || saveInProgress)
|
||||
? "autosave-incomplete"
|
||||
: "autosave-complete"
|
||||
: this.needToSave() || saveInProgress
|
||||
? "autosave-incomplete"
|
||||
: "autosave-complete"
|
||||
}
|
||||
style={{
|
||||
position: "fixed",
|
||||
display: "inherit",
|
||||
right: globals.leftSidebarWidth + 5,
|
||||
bottom: 5
|
||||
bottom: 5,
|
||||
}}
|
||||
>
|
||||
{this.statusMessage()}
|
||||
|
||||
@@ -2,11 +2,11 @@ import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Button, Tooltip, Dialog, Classes, Colors } from "@blueprintjs/core";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
annotations: state.annotations,
|
||||
universe: state.universe
|
||||
universe: state.universe,
|
||||
}))
|
||||
class AnnoDialog extends React.PureComponent {
|
||||
constructor(props) {
|
||||
@@ -30,13 +30,13 @@ class AnnoDialog extends React.PureComponent {
|
||||
primaryButtonText,
|
||||
secondaryButtonText,
|
||||
handleSecondaryButtonSubmit,
|
||||
primaryButtonProps
|
||||
primaryButtonProps,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Dialog icon="tag" title={title} isOpen={isActive} onClose={handleCancel}>
|
||||
<form
|
||||
onSubmit={e => {
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
@@ -48,7 +48,7 @@ class AnnoDialog extends React.PureComponent {
|
||||
style={{
|
||||
marginTop: 7,
|
||||
visibility: validationError ? "visible" : "hidden",
|
||||
color: Colors.ORANGE3
|
||||
color: Colors.ORANGE3,
|
||||
}}
|
||||
>
|
||||
{errorMessage}
|
||||
|
||||
@@ -3,11 +3,11 @@ import { connect } from "react-redux";
|
||||
import { Button, MenuItem } from "@blueprintjs/core";
|
||||
import { Select } from "@blueprintjs/select";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
annotations: state.annotations,
|
||||
universe: state.universe
|
||||
universe: state.universe,
|
||||
}))
|
||||
class DuplicateCategorySelect extends React.PureComponent {
|
||||
constructor(props) {
|
||||
@@ -19,7 +19,7 @@ class DuplicateCategorySelect extends React.PureComponent {
|
||||
const {
|
||||
allCategoryNames,
|
||||
categoryToDuplicate,
|
||||
handleModalDuplicateCategorySelection
|
||||
handleModalDuplicateCategorySelection,
|
||||
} = this.props;
|
||||
return (
|
||||
<div>
|
||||
@@ -37,7 +37,7 @@ class DuplicateCategorySelect extends React.PureComponent {
|
||||
return <MenuItem onClick={handleClick} key={d} text={d} />;
|
||||
}}
|
||||
noResults={<MenuItem disabled text="No results." />}
|
||||
onItemSelect={d => {
|
||||
onItemSelect={(d) => {
|
||||
handleModalDuplicateCategorySelection(d);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -6,11 +6,11 @@ import {
|
||||
MenuItem,
|
||||
Popover,
|
||||
Position,
|
||||
PopoverInteractionKind
|
||||
PopoverInteractionKind,
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
@connect(state => ({
|
||||
annotations: state.annotations
|
||||
@connect((state) => ({
|
||||
annotations: state.annotations,
|
||||
}))
|
||||
class AnnoMenuCategory extends React.PureComponent {
|
||||
constructor(props) {
|
||||
@@ -22,7 +22,7 @@ class AnnoMenuCategory extends React.PureComponent {
|
||||
const { dispatch, metadataField } = this.props;
|
||||
dispatch({
|
||||
type: "annotation: activate add new label mode",
|
||||
data: metadataField
|
||||
data: metadataField,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ class AnnoMenuCategory extends React.PureComponent {
|
||||
|
||||
dispatch({
|
||||
type: "annotation: activate category edit mode",
|
||||
data: metadataField
|
||||
data: metadataField,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ class AnnoMenuCategory extends React.PureComponent {
|
||||
const { dispatch, metadataField } = this.props;
|
||||
dispatch({
|
||||
type: "annotation: delete category",
|
||||
metadataField
|
||||
metadataField,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ class AnnoMenuCategory extends React.PureComponent {
|
||||
isUserAnno,
|
||||
createText,
|
||||
editText,
|
||||
deleteText
|
||||
deleteText,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
|
||||
@@ -31,7 +31,7 @@ export default class LabelInput extends React.PureComponent {
|
||||
const queryResults = this.filterLabels(query);
|
||||
this.state = {
|
||||
query,
|
||||
queryResults
|
||||
queryResults,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export default class LabelInput extends React.PureComponent {
|
||||
const queryResults = this.filterLabels(query);
|
||||
this.setState({
|
||||
query,
|
||||
queryResults
|
||||
queryResults,
|
||||
});
|
||||
|
||||
const { onChange } = this.props;
|
||||
@@ -57,7 +57,7 @@ export default class LabelInput extends React.PureComponent {
|
||||
if (target !== query && onSelect) onSelect(target, event);
|
||||
};
|
||||
|
||||
handleKeyDown = e => {
|
||||
handleKeyDown = (e) => {
|
||||
/*
|
||||
prevent these events from propagating to containing form/dialog
|
||||
and causing further side effects (eg, closing dialog, submitting
|
||||
@@ -72,7 +72,7 @@ export default class LabelInput extends React.PureComponent {
|
||||
}
|
||||
};
|
||||
|
||||
handleChange = e => {
|
||||
handleChange = (e) => {
|
||||
const { onChange } = this.props;
|
||||
if (onChange) onChange(e.target.value);
|
||||
};
|
||||
@@ -112,16 +112,18 @@ export default class LabelInput extends React.PureComponent {
|
||||
|
||||
/* empty query is wildcard */
|
||||
if (query === "") {
|
||||
return labelSuggestions.slice(0, LabelInput.QueryResultLimit).map(l => ({
|
||||
target: l,
|
||||
score: -10000
|
||||
}));
|
||||
return labelSuggestions
|
||||
.slice(0, LabelInput.QueryResultLimit)
|
||||
.map((l) => ({
|
||||
target: l,
|
||||
score: -10000,
|
||||
}));
|
||||
}
|
||||
|
||||
/* else, do a fuzzy query */
|
||||
const options = {
|
||||
limit: LabelInput.QueryResultLimit,
|
||||
threshold: -10000 // don't return bad results
|
||||
threshold: -10000, // don't return bad results
|
||||
};
|
||||
let queryResults = fuzzysort.go(query, labelSuggestions, options);
|
||||
/* exact match will always be first in list */
|
||||
@@ -149,18 +151,18 @@ export default class LabelInput extends React.PureComponent {
|
||||
|
||||
const popoverProps = {
|
||||
minimal: true,
|
||||
...props.popoverProps
|
||||
...props.popoverProps,
|
||||
};
|
||||
const inputProps = {
|
||||
...props.inputProps,
|
||||
autoFocus: false
|
||||
autoFocus: false,
|
||||
};
|
||||
const { queryResults } = this.state;
|
||||
return (
|
||||
<>
|
||||
<Suggest
|
||||
fill
|
||||
inputValueRenderer={i => i.target}
|
||||
inputValueRenderer={(i) => i.target}
|
||||
items={queryResults}
|
||||
itemRenderer={this.renderLabelSuggestion}
|
||||
onItemSelect={this.handleItemSelect}
|
||||
|
||||
@@ -4,60 +4,60 @@ import { Colors } from "@blueprintjs/core";
|
||||
import { AnnotationsHelpers } from "../../util/stateManager";
|
||||
|
||||
export function isLabelErroneous(label, metadataField, ontology, schema) {
|
||||
/*
|
||||
/*
|
||||
return false if this is a LEGAL/acceptable category name or NULL/empty string,
|
||||
or return an error type.
|
||||
*/
|
||||
|
||||
/* allow empty string */
|
||||
if (label === "") return false;
|
||||
/* allow empty string */
|
||||
if (label === "") return false;
|
||||
|
||||
/* check for label syntax errors, but allow terms in ontology */
|
||||
const termInOntology = ontology?.termSet.has(label) ?? false;
|
||||
const error = AnnotationsHelpers.annotationNameIsErroneous(label);
|
||||
if (error && !termInOntology) return error;
|
||||
/* check for label syntax errors, but allow terms in ontology */
|
||||
const termInOntology = ontology?.termSet.has(label) ?? false;
|
||||
const error = AnnotationsHelpers.annotationNameIsErroneous(label);
|
||||
if (error && !termInOntology) return error;
|
||||
|
||||
/* disallow duplicates */
|
||||
const { obsByName } = schema.annotations;
|
||||
if (obsByName[metadataField].categories.indexOf(label) !== -1)
|
||||
return "duplicate";
|
||||
/* disallow duplicates */
|
||||
const { obsByName } = schema.annotations;
|
||||
if (obsByName[metadataField].categories.indexOf(label) !== -1)
|
||||
return "duplicate";
|
||||
|
||||
/* otherwise, no error */
|
||||
return false;
|
||||
/* otherwise, no error */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* all other errors - map code to human error message */
|
||||
const errorMessageMap = {
|
||||
"empty-string": "Blank names not allowed",
|
||||
duplicate: "Name must be unique",
|
||||
"trim-spaces": "Leading and trailing spaces not allowed",
|
||||
"illegal-characters":
|
||||
"Only alphanumeric and special characters (-_.) allowed",
|
||||
"multi-space-run": "Multiple consecutive spaces not allowed"
|
||||
"empty-string": "Blank names not allowed",
|
||||
duplicate: "Name must be unique",
|
||||
"trim-spaces": "Leading and trailing spaces not allowed",
|
||||
"illegal-characters":
|
||||
"Only alphanumeric and special characters (-_.) allowed",
|
||||
"multi-space-run": "Multiple consecutive spaces not allowed",
|
||||
};
|
||||
|
||||
export function labelPrompt(err, prolog, epilog) {
|
||||
let errPrompt = null;
|
||||
if (err) {
|
||||
let errMsg = errorMessageMap[err] ?? "error";
|
||||
errMsg = errMsg[0].toLowerCase() + errMsg.slice(1);
|
||||
errPrompt = (
|
||||
<span
|
||||
style={{
|
||||
marginTop: 7,
|
||||
color: Colors.ORANGE3
|
||||
}}
|
||||
>
|
||||
{errMsg}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
{prolog}
|
||||
{err ? " - " : null}
|
||||
{errPrompt}
|
||||
{epilog}
|
||||
</span>
|
||||
);
|
||||
let errPrompt = null;
|
||||
if (err) {
|
||||
let errMsg = errorMessageMap[err] ?? "error";
|
||||
errMsg = errMsg[0].toLowerCase() + errMsg.slice(1);
|
||||
errPrompt = (
|
||||
<span
|
||||
style={{
|
||||
marginTop: 7,
|
||||
color: Colors.ORANGE3,
|
||||
}}
|
||||
>
|
||||
{errMsg}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span>
|
||||
{prolog}
|
||||
{err ? " - " : null}
|
||||
{errPrompt}
|
||||
{epilog}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ const setupParallelCoordinates = (width, height, margin) => {
|
||||
|
||||
return {
|
||||
svg,
|
||||
ctx
|
||||
ctx,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export const innerHeight = height - 2;
|
||||
|
||||
export const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
|
||||
export const createDimensions = data => {
|
||||
export const createDimensions = (data) => {
|
||||
const newArr = [];
|
||||
_.each(data, (value, key) => {
|
||||
if (value.range) {
|
||||
@@ -21,12 +21,12 @@ export const createDimensions = data => {
|
||||
key /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */,
|
||||
type: {
|
||||
within: (d, extent, dim) =>
|
||||
extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]
|
||||
extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1],
|
||||
},
|
||||
scale: d3
|
||||
.scaleSqrt()
|
||||
.range([innerHeight, 0])
|
||||
.domain([0, value.range.max])
|
||||
.domain([0, value.range.max]),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -38,12 +38,12 @@ const continuous = (selectorId, colorscale, colorAccessor) => {
|
||||
.range([1, legendheight - margin.top - margin.bottom])
|
||||
.domain([
|
||||
colorscale.domain()[1],
|
||||
colorscale.domain()[0]
|
||||
colorscale.domain()[0],
|
||||
]); /* we flip this to make viridis colors dark if high in the color scale */
|
||||
|
||||
// image data hackery based on http://bl.ocks.org/mbostock/048d21cf747371b11884f75ad896e5a5
|
||||
const image = ctx.createImageData(1, legendheight);
|
||||
d3.range(legendheight).forEach(i => {
|
||||
d3.range(legendheight).forEach((i) => {
|
||||
const c = d3.rgb(colorscale(legendscale.invert(i)));
|
||||
image.data[4 * i] = c.r;
|
||||
image.data[4 * i + 1] = c.g;
|
||||
@@ -62,11 +62,7 @@ const continuous = (selectorId, colorscale, colorAccessor) => {
|
||||
});
|
||||
*/
|
||||
|
||||
const legendaxis = d3
|
||||
.axisRight()
|
||||
.scale(legendscale)
|
||||
.tickSize(6)
|
||||
.ticks(8);
|
||||
const legendaxis = d3.axisRight().scale(legendscale).tickSize(6).ticks(8);
|
||||
|
||||
const svg = d3
|
||||
.select(selectorId)
|
||||
@@ -98,10 +94,10 @@ const continuous = (selectorId, colorscale, colorAccessor) => {
|
||||
.text(colorAccessor);
|
||||
};
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
colorScale: state.colors.scale,
|
||||
responsive: state.responsive
|
||||
responsive: state.responsive,
|
||||
}))
|
||||
class ContinuousLegend extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -118,9 +114,7 @@ class ContinuousLegend extends React.Component {
|
||||
prevProps.responsive.width !== responsive.width
|
||||
) {
|
||||
/* always remove it, if it's not continuous we don't put it back. */
|
||||
d3.select("#continuous_legend")
|
||||
.selectAll("*")
|
||||
.remove();
|
||||
d3.select("#continuous_legend").selectAll("*").remove();
|
||||
}
|
||||
|
||||
if (colorAccessor && colorScale && colorScale.range) {
|
||||
@@ -144,7 +138,7 @@ class ContinuousLegend extends React.Component {
|
||||
position: "fixed",
|
||||
display: colorAccessor ? "inherit" : "none",
|
||||
right: globals.leftSidebarWidth,
|
||||
top: responsive.height / 2
|
||||
top: responsive.height / 2,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
|
||||
import styles from "./container.css";
|
||||
|
||||
const Container = props => {
|
||||
const Container = (props) => {
|
||||
const { children } = props;
|
||||
return <div className={styles.container}>{children}</div>;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import * as globals from "../../globals";
|
||||
|
||||
const Logo = props => {
|
||||
const Logo = (props) => {
|
||||
const { size } = props;
|
||||
return (
|
||||
<svg width={size} height={size} viewBox="0 0 48 48" fill="none">
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Button,
|
||||
FormGroup,
|
||||
InputGroup,
|
||||
ControlGroup
|
||||
ControlGroup,
|
||||
} from "@blueprintjs/core";
|
||||
import { Suggest } from "@blueprintjs/select";
|
||||
import HistogramBrush from "../brushableHistogram";
|
||||
@@ -19,7 +19,7 @@ import * as globals from "../../globals";
|
||||
import actions from "../../actions";
|
||||
import {
|
||||
postUserErrorToast,
|
||||
keepAroundErrorToast
|
||||
keepAroundErrorToast,
|
||||
} from "../framework/toasters";
|
||||
|
||||
import { memoize } from "../../util/dataframe/util";
|
||||
@@ -40,7 +40,7 @@ const renderGene = (fuzzySortResult, { handleClick, modifiers }) => {
|
||||
// See https://github.com/chanzuckerberg/cellxgene/issues/483
|
||||
// label={gene.n_counts}
|
||||
key={geneName}
|
||||
onClick={g =>
|
||||
onClick={(g) =>
|
||||
/* this fires when user clicks a menu item */
|
||||
handleClick(g)
|
||||
}
|
||||
@@ -53,17 +53,17 @@ const filterGenes = (query, genes) =>
|
||||
/* fires on load, once, and then for each character typed into the input */
|
||||
fuzzysort.go(query, genes, {
|
||||
limit: 5,
|
||||
threshold: -10000 // don't return bad results
|
||||
threshold: -10000, // don't return bad results
|
||||
});
|
||||
|
||||
@connect(state => {
|
||||
@connect((state) => {
|
||||
return {
|
||||
obsAnnotations: state.world?.obsAnnotations,
|
||||
userDefinedGenes: state.controls.userDefinedGenes,
|
||||
userDefinedGenesLoading: state.controls.userDefinedGenesLoading,
|
||||
world: state.world,
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
differential: state.differential
|
||||
differential: state.differential,
|
||||
};
|
||||
})
|
||||
class GeneExpression extends React.Component {
|
||||
@@ -72,11 +72,11 @@ class GeneExpression extends React.Component {
|
||||
this.state = {
|
||||
bulkAdd: "",
|
||||
tab: "autosuggest",
|
||||
activeItem: null
|
||||
activeItem: null,
|
||||
};
|
||||
}
|
||||
|
||||
_genesToUpper = listGenes => {
|
||||
_genesToUpper = (listGenes) => {
|
||||
// Has to be a Map to preserve index
|
||||
const upperGenes = new Map();
|
||||
for (let i = 0, { length } = listGenes; i < length; i += 1) {
|
||||
@@ -87,7 +87,7 @@ class GeneExpression extends React.Component {
|
||||
};
|
||||
|
||||
// eslint-disable-next-line react/sort-comp
|
||||
_memoGenesToUpper = memoize(this._genesToUpper, arr => arr);
|
||||
_memoGenesToUpper = memoize(this._genesToUpper, (arr) => arr);
|
||||
|
||||
handleBulkAddClick = () => {
|
||||
const { world, dispatch, userDefinedGenes } = this.props;
|
||||
@@ -115,7 +115,7 @@ class GeneExpression extends React.Component {
|
||||
dispatch({ type: "bulk user defined gene start" });
|
||||
|
||||
Promise.all(
|
||||
[...upperGenes.keys()].map(upperGene => {
|
||||
[...upperGenes.keys()].map((upperGene) => {
|
||||
if (upperUserDefinedGenes.get(upperGene) !== undefined) {
|
||||
return keepAroundErrorToast("That gene already exists");
|
||||
}
|
||||
@@ -204,7 +204,7 @@ class GeneExpression extends React.Component {
|
||||
world,
|
||||
userDefinedGenes,
|
||||
userDefinedGenesLoading,
|
||||
differential
|
||||
differential,
|
||||
} = this.props;
|
||||
const varIndexName = world?.schema?.annotations?.var?.index;
|
||||
const varIndex = world?.varAnnotations?.col(varIndexName)?.asArray();
|
||||
@@ -218,7 +218,7 @@ class GeneExpression extends React.Component {
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
padding: globals.leftSidebarSectionPadding
|
||||
padding: globals.leftSidebarSectionPadding,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
@@ -250,7 +250,7 @@ class GeneExpression extends React.Component {
|
||||
<ControlGroup
|
||||
style={{
|
||||
paddingLeft: globals.leftSidebarSectionPadding,
|
||||
paddingBottom: globals.leftSidebarSectionPadding
|
||||
paddingBottom: globals.leftSidebarSectionPadding,
|
||||
}}
|
||||
>
|
||||
<Suggest
|
||||
@@ -261,7 +261,7 @@ class GeneExpression extends React.Component {
|
||||
userDefinedGenesLoading ? () => true : () => false
|
||||
}
|
||||
noResults={<MenuItem disabled text="No matching genes." />}
|
||||
onItemSelect={g => {
|
||||
onItemSelect={(g) => {
|
||||
/* this happens on 'enter' */
|
||||
this.handleClick(g);
|
||||
}}
|
||||
@@ -271,7 +271,9 @@ class GeneExpression extends React.Component {
|
||||
return "";
|
||||
}}
|
||||
itemListPredicate={filterGenes}
|
||||
onActiveItemChange={item => this.setState({ activeItem: item })}
|
||||
onActiveItemChange={(item) =>
|
||||
this.setState({ activeItem: item })
|
||||
}
|
||||
itemRenderer={renderGene.bind(this)}
|
||||
items={varIndex || ["No genes"]}
|
||||
popoverProps={{ minimal: true }}
|
||||
@@ -289,7 +291,7 @@ class GeneExpression extends React.Component {
|
||||
{tab === "bulkadd" ? (
|
||||
<div style={{ paddingLeft: globals.leftSidebarSectionPadding }}>
|
||||
<form
|
||||
onSubmit={e => {
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
this.handleBulkAddClick();
|
||||
}}
|
||||
@@ -300,7 +302,7 @@ class GeneExpression extends React.Component {
|
||||
>
|
||||
<ControlGroup>
|
||||
<InputGroup
|
||||
onChange={e => {
|
||||
onChange={(e) => {
|
||||
this.setState({ bulkAdd: e.target.value });
|
||||
}}
|
||||
id="text-input-bulk-add"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { glPointFlags, glPointSize } from "../../util/glHelpers";
|
||||
|
||||
export default function(regl) {
|
||||
export default function (regl) {
|
||||
return regl({
|
||||
vert: `
|
||||
precision mediump float;
|
||||
@@ -54,18 +54,18 @@ export default function(regl) {
|
||||
attributes: {
|
||||
position: regl.prop("position"),
|
||||
color: regl.prop("color"),
|
||||
flag: regl.prop("flag")
|
||||
flag: regl.prop("flag"),
|
||||
},
|
||||
|
||||
uniforms: {
|
||||
distance: regl.prop("distance"),
|
||||
projView: regl.prop("projView"),
|
||||
nPoints: regl.prop("nPoints"),
|
||||
minViewportDimension: regl.prop("minViewportDimension")
|
||||
minViewportDimension: regl.prop("minViewportDimension"),
|
||||
},
|
||||
|
||||
count: regl.prop("count"),
|
||||
|
||||
primitive: "points"
|
||||
primitive: "points",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -34,12 +34,12 @@ function createProjectionTF(viewportWidth, viewportHeight) {
|
||||
const minDim = Math.min(viewportWidth, heightMinusGutter);
|
||||
const aspectScale = [
|
||||
(fractionToUse * minDim) / viewportWidth,
|
||||
(fractionToUse * minDim) / viewportHeight
|
||||
(fractionToUse * minDim) / viewportHeight,
|
||||
];
|
||||
const m = mat3.create();
|
||||
mat3.fromTranslation(m, [
|
||||
0,
|
||||
-topGutterSizePx / viewportHeight / aspectScale[1]
|
||||
-topGutterSizePx / viewportHeight / aspectScale[1],
|
||||
]);
|
||||
mat3.scale(m, m, aspectScale);
|
||||
return m;
|
||||
@@ -73,7 +73,7 @@ function renderThrottle(callback) {
|
||||
};
|
||||
}
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
universe: state.universe,
|
||||
world: state.world,
|
||||
crossfilter: state.crossfilter,
|
||||
@@ -85,7 +85,7 @@ function renderThrottle(callback) {
|
||||
centroidLabels: state.centroidLabels,
|
||||
graphInteractionMode: state.controls.graphInteractionMode,
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
pointDilation: state.pointDilation
|
||||
pointDilation: state.pointDilation,
|
||||
}))
|
||||
class Graph extends React.Component {
|
||||
computePointPositions = memoize((X, Y, modelTF) => {
|
||||
@@ -102,7 +102,7 @@ class Graph extends React.Component {
|
||||
return positions;
|
||||
});
|
||||
|
||||
computePointColors = memoize(rgb => {
|
||||
computePointColors = memoize((rgb) => {
|
||||
/*
|
||||
compute webgl colors for each point
|
||||
*/
|
||||
@@ -186,13 +186,13 @@ class Graph extends React.Component {
|
||||
positions: null,
|
||||
colors: null,
|
||||
sizes: null,
|
||||
flags: null
|
||||
flags: null,
|
||||
};
|
||||
this.state = {
|
||||
toolSVG: null,
|
||||
tool: null,
|
||||
container: null,
|
||||
cameraRender: 0
|
||||
cameraRender: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ class Graph extends React.Component {
|
||||
camera,
|
||||
modelTF,
|
||||
modelInvTF: mat3.invert([], modelTF),
|
||||
projectionTF
|
||||
projectionTF,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ class Graph extends React.Component {
|
||||
layoutChoice,
|
||||
graphInteractionMode,
|
||||
pointDilation,
|
||||
colorAccessor
|
||||
colorAccessor,
|
||||
} = this.props;
|
||||
const { regl, toolSVG, camera, modelTF } = this.state;
|
||||
let stateChanges = {};
|
||||
@@ -274,7 +274,7 @@ class Graph extends React.Component {
|
||||
needsRepaint = true;
|
||||
stateChanges = {
|
||||
...stateChanges,
|
||||
projectionTF
|
||||
projectionTF,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ class Graph extends React.Component {
|
||||
// If the window size has changed we want to recreate all SVGs
|
||||
stateChanges = {
|
||||
...stateChanges,
|
||||
...this.createToolSVG()
|
||||
...this.createToolSVG(),
|
||||
};
|
||||
} else if (
|
||||
(responsive.height && responsive.width && !toolSVG) ||
|
||||
@@ -345,7 +345,7 @@ class Graph extends React.Component {
|
||||
// If lasso/zoom is switched
|
||||
stateChanges = {
|
||||
...stateChanges,
|
||||
...this.createToolSVG()
|
||||
...this.createToolSVG(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -369,12 +369,12 @@ class Graph extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleCanvasEvent = e => {
|
||||
handleCanvasEvent = (e) => {
|
||||
const { camera, projectionTF } = this.state;
|
||||
if (e.type !== "wheel") e.preventDefault();
|
||||
if (camera.handleEvent(e, projectionTF)) {
|
||||
this.renderCanvas();
|
||||
this.setState(state => {
|
||||
this.setState((state) => {
|
||||
return { ...state, updateOverlay: !state.updateOverlay };
|
||||
});
|
||||
}
|
||||
@@ -389,9 +389,7 @@ class Graph extends React.Component {
|
||||
|
||||
/* clear out whatever was on the div, even if nothing, but usually the brushes etc */
|
||||
|
||||
d3.select("#lasso-layer")
|
||||
.selectAll(".lasso-group")
|
||||
.remove();
|
||||
d3.select("#lasso-layer").selectAll(".lasso-group").remove();
|
||||
|
||||
// Don't render or recreate toolSVG if currently in zoom mode
|
||||
if (graphInteractionMode !== "select") {
|
||||
@@ -443,7 +441,7 @@ class Graph extends React.Component {
|
||||
*/
|
||||
const screenCoords = [
|
||||
this.mapPointToScreen(currentSelection.brushCoords.northwest),
|
||||
this.mapPointToScreen(currentSelection.brushCoords.southeast)
|
||||
this.mapPointToScreen(currentSelection.brushCoords.southeast),
|
||||
];
|
||||
if (!toolCurrentSelection) {
|
||||
/* tool is not selected, so just move the brush */
|
||||
@@ -480,7 +478,7 @@ class Graph extends React.Component {
|
||||
/*
|
||||
if there is a current selection, make sure the lasso tool matches
|
||||
*/
|
||||
const polygon = currentSelection.polygon.map(p =>
|
||||
const polygon = currentSelection.polygon.map((p) =>
|
||||
this.mapPointToScreen(p)
|
||||
);
|
||||
tool.move(polygon);
|
||||
@@ -551,7 +549,7 @@ class Graph extends React.Component {
|
||||
),
|
||||
Math.round(
|
||||
-((xy[1] + 1) / 2 - 1) * (responsive.height - this.graphPaddingTop)
|
||||
)
|
||||
),
|
||||
];
|
||||
return pin;
|
||||
}
|
||||
@@ -571,12 +569,12 @@ class Graph extends React.Component {
|
||||
const s = d3.event.selection;
|
||||
const brushCoords = {
|
||||
northwest: this.mapScreenToPoint([s[0][0], s[0][1]]),
|
||||
southeast: this.mapScreenToPoint([s[1][0], s[1][1]])
|
||||
southeast: this.mapScreenToPoint([s[1][0], s[1][1]]),
|
||||
};
|
||||
|
||||
dispatch({
|
||||
type: "graph brush change",
|
||||
brushCoords
|
||||
brushCoords,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -601,15 +599,15 @@ class Graph extends React.Component {
|
||||
if (s) {
|
||||
const brushCoords = {
|
||||
northwest: this.mapScreenToPoint(s[0]),
|
||||
southeast: this.mapScreenToPoint(s[1])
|
||||
southeast: this.mapScreenToPoint(s[1]),
|
||||
};
|
||||
dispatch({
|
||||
type: "graph brush end",
|
||||
brushCoords
|
||||
brushCoords,
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: "graph brush deselect"
|
||||
type: "graph brush deselect",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -617,14 +615,14 @@ class Graph extends React.Component {
|
||||
handleBrushDeselectAction() {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({
|
||||
type: "graph brush deselect"
|
||||
type: "graph brush deselect",
|
||||
});
|
||||
}
|
||||
|
||||
handleLassoStart() {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({
|
||||
type: "graph lasso start"
|
||||
type: "graph lasso start",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -642,7 +640,7 @@ class Graph extends React.Component {
|
||||
} else {
|
||||
dispatch({
|
||||
type: "graph lasso end",
|
||||
polygon: polygon.map(xy => this.mapScreenToPoint(xy)) // transform the polygon
|
||||
polygon: polygon.map((xy) => this.mapScreenToPoint(xy)), // transform the polygon
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -667,7 +665,7 @@ class Graph extends React.Component {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({
|
||||
type: "change opacity deselected cells in 2d graph background",
|
||||
data: e.target.value
|
||||
data: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -688,7 +686,7 @@ class Graph extends React.Component {
|
||||
regl.poll();
|
||||
regl.clear({
|
||||
depth: 1,
|
||||
color: [1, 1, 1, 1]
|
||||
color: [1, 1, 1, 1],
|
||||
});
|
||||
drawPoints({
|
||||
distance: camera.distance(),
|
||||
@@ -698,7 +696,7 @@ class Graph extends React.Component {
|
||||
count: this.count,
|
||||
projView,
|
||||
nPoints: universe.nObs,
|
||||
minViewportDimension: Math.min(width || 800, height || 600)
|
||||
minViewportDimension: Math.min(width || 800, height || 600),
|
||||
});
|
||||
regl._gl.flush();
|
||||
}
|
||||
@@ -711,7 +709,7 @@ class Graph extends React.Component {
|
||||
pointBuffer,
|
||||
flagBuffer,
|
||||
camera,
|
||||
projectionTF
|
||||
projectionTF,
|
||||
} = this.state;
|
||||
this.renderPoints(
|
||||
regl,
|
||||
@@ -737,7 +735,7 @@ class Graph extends React.Component {
|
||||
zIndex: -9999,
|
||||
position: "fixed",
|
||||
top: this.graphPaddingTop,
|
||||
right: globals.leftSidebarWidth
|
||||
right: globals.leftSidebarWidth,
|
||||
}}
|
||||
>
|
||||
<div id="graphAttachPoint">
|
||||
@@ -774,7 +772,7 @@ class Graph extends React.Component {
|
||||
width={responsive.width - this.graphPaddingRightLeft}
|
||||
height={responsive.height - this.graphPaddingTop}
|
||||
data-testid="layout-graph"
|
||||
ref={canvas => {
|
||||
ref={(canvas) => {
|
||||
this.reglCanvas = canvas;
|
||||
}}
|
||||
onMouseDown={this.handleCanvasEvent}
|
||||
|
||||
@@ -6,14 +6,14 @@ import { connect } from "react-redux";
|
||||
import { categoryLabelDisplayStringLongLength } from "../../../globals";
|
||||
|
||||
export default
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
colorAccessor: state.colors.colorAccessor,
|
||||
dilatedValue: state.pointDilation.categoryField,
|
||||
labels: state.centroidLabels.labels
|
||||
labels: state.centroidLabels.labels,
|
||||
}))
|
||||
class CentroidLabels extends PureComponent {
|
||||
// Check to see if centroids have either just been displayed or removed from the overlay
|
||||
componentDidUpdate = prevProps => {
|
||||
componentDidUpdate = (prevProps) => {
|
||||
const { labels, overlayToggled } = this.props;
|
||||
const prevSize = prevProps.labels.size;
|
||||
const { size } = labels;
|
||||
@@ -33,7 +33,7 @@ class CentroidLabels extends PureComponent {
|
||||
inverseTransform,
|
||||
dilatedValue,
|
||||
dispatch,
|
||||
colorAccessor
|
||||
colorAccessor,
|
||||
} = this.props;
|
||||
|
||||
const labelSVGS = [];
|
||||
@@ -74,20 +74,20 @@ class CentroidLabels extends PureComponent {
|
||||
fontSize,
|
||||
fontWeight,
|
||||
fill: "black",
|
||||
userSelect: "none"
|
||||
userSelect: "none",
|
||||
}}
|
||||
onMouseEnter={e =>
|
||||
onMouseEnter={(e) =>
|
||||
dispatch({
|
||||
type: "category value mouse hover start",
|
||||
metadataField: colorAccessor,
|
||||
categoryField: e.target.getAttribute("data-label")
|
||||
categoryField: e.target.getAttribute("data-label"),
|
||||
})
|
||||
}
|
||||
onMouseOut={e =>
|
||||
onMouseOut={(e) =>
|
||||
dispatch({
|
||||
type: "category value mouse hover end",
|
||||
metadataField: colorAccessor,
|
||||
categoryField: e.target.getAttribute("data-label")
|
||||
categoryField: e.target.getAttribute("data-label"),
|
||||
})
|
||||
}
|
||||
pointerEvents="visiblePainted"
|
||||
|
||||
@@ -4,8 +4,8 @@ import { connect } from "react-redux";
|
||||
import styles from "../graph.css";
|
||||
|
||||
export default
|
||||
@connect(state => ({
|
||||
responsive: state.responsive
|
||||
@connect((state) => ({
|
||||
responsive: state.responsive,
|
||||
}))
|
||||
class GraphOverlayLayer extends PureComponent {
|
||||
/*
|
||||
@@ -18,11 +18,11 @@ class GraphOverlayLayer extends PureComponent {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
display: {}
|
||||
display: {},
|
||||
};
|
||||
}
|
||||
|
||||
matrixToTransformString = m => {
|
||||
matrixToTransformString = (m) => {
|
||||
/*
|
||||
Translates the gl-matrix mat3 to SVG matrix transform style
|
||||
|
||||
@@ -34,13 +34,13 @@ class GraphOverlayLayer extends PureComponent {
|
||||
return `matrix(${m[0]} ${m[1]} ${m[3]} ${m[4]} ${m[6]} ${m[7]})`;
|
||||
};
|
||||
|
||||
reverseMatrixScaleTransformString = m => {
|
||||
reverseMatrixScaleTransformString = (m) => {
|
||||
return `matrix(${1 / m[0]} 0 0 ${1 / m[4]} 0 0)`;
|
||||
};
|
||||
|
||||
// This is passed to all children, should be called when an overlay's display state is toggled along with the overlay name and its new display state in boolean form
|
||||
overlayToggled = (overlay, displaying) => {
|
||||
this.setState(state => {
|
||||
this.setState((state) => {
|
||||
return { ...state, display: { ...state.display, [overlay]: displaying } };
|
||||
});
|
||||
};
|
||||
@@ -54,13 +54,13 @@ class GraphOverlayLayer extends PureComponent {
|
||||
graphPaddingRightLeft,
|
||||
graphPaddingTop,
|
||||
children,
|
||||
handleCanvasEvent
|
||||
handleCanvasEvent,
|
||||
} = this.props;
|
||||
|
||||
if (!cameraTF) return null;
|
||||
|
||||
const { display } = this.state;
|
||||
const displaying = Object.values(display).some(value => value); // check to see if at least one overlay is currently displayed
|
||||
const displaying = Object.values(display).some((value) => value); // check to see if at least one overlay is currently displayed
|
||||
|
||||
const inverseTransform = `${this.reverseMatrixScaleTransformString(
|
||||
modelTF
|
||||
@@ -68,15 +68,15 @@ class GraphOverlayLayer extends PureComponent {
|
||||
cameraTF
|
||||
)} ${this.reverseMatrixScaleTransformString(
|
||||
projectionTF
|
||||
)} scale(1 2) scale(1 ${1 /
|
||||
-(responsive.height - graphPaddingTop)}) scale(2 1) scale(${1 /
|
||||
(responsive.width - graphPaddingRightLeft)} 1)`;
|
||||
)} scale(1 2) scale(1 ${
|
||||
1 / -(responsive.height - graphPaddingTop)
|
||||
}) scale(2 1) scale(${1 / (responsive.width - graphPaddingRightLeft)} 1)`;
|
||||
|
||||
// Copy the children passed with the overlay and add the inverse transform and onDisplayChange props
|
||||
const newChildren = React.Children.map(children, child =>
|
||||
const newChildren = React.Children.map(children, (child) =>
|
||||
cloneElement(child, {
|
||||
inverseTransform,
|
||||
overlayToggled: this.overlayToggled
|
||||
overlayToggled: this.overlayToggled,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -88,15 +88,16 @@ class GraphOverlayLayer extends PureComponent {
|
||||
pointerEvents="none"
|
||||
style={{
|
||||
zIndex: 99,
|
||||
backgroundColor: displaying ? "rgba(255, 255, 255, 0.55)" : ""
|
||||
backgroundColor: displaying ? "rgba(255, 255, 255, 0.55)" : "",
|
||||
}}
|
||||
onMouseMove={handleCanvasEvent}
|
||||
onWheel={handleCanvasEvent}
|
||||
>
|
||||
<g
|
||||
id="canvas-transformation-group-x"
|
||||
transform={`scale(${responsive.width -
|
||||
graphPaddingRightLeft} 1) scale(.5 1) translate(1 0)`}
|
||||
transform={`scale(${
|
||||
responsive.width - graphPaddingRightLeft
|
||||
} 1) scale(.5 1) translate(1 0)`}
|
||||
>
|
||||
<g
|
||||
id="canvas-transformation-group-y"
|
||||
|
||||
@@ -5,8 +5,8 @@ import * as d3 from "d3";
|
||||
const Lasso = () => {
|
||||
const dispatch = d3.dispatch("start", "end", "cancel");
|
||||
|
||||
const polygonToPath = polygon =>
|
||||
`M${polygon.map(d => d.join(",")).join("L")}`;
|
||||
const polygonToPath = (polygon) =>
|
||||
`M${polygon.map((d) => d.join(",")).join("L")}`;
|
||||
|
||||
const distance = (pt1, pt2) =>
|
||||
Math.sqrt((pt2[0] - pt1[0]) ** 2 + (pt2[1] - pt1[1]) ** 2);
|
||||
@@ -14,7 +14,7 @@ const Lasso = () => {
|
||||
// distance last point has to be to first point before it auto closes when mouse is released
|
||||
const closeDistance = 75;
|
||||
|
||||
const lasso = svg => {
|
||||
const lasso = (svg) => {
|
||||
let lassoPolygon;
|
||||
let lassoPath;
|
||||
let closePath;
|
||||
@@ -55,10 +55,7 @@ const Lasso = () => {
|
||||
distance(lassoPolygon[0], lassoPolygon[lassoPolygon.length - 1]) <
|
||||
closeDistance
|
||||
) {
|
||||
closePath
|
||||
.attr("x1", point[0])
|
||||
.attr("y1", point[1])
|
||||
.attr("opacity", 1);
|
||||
closePath.attr("x1", point[0]).attr("y1", point[1]).attr("opacity", 1);
|
||||
} else {
|
||||
closePath.attr("opacity", 0);
|
||||
}
|
||||
@@ -116,7 +113,7 @@ const Lasso = () => {
|
||||
}
|
||||
};
|
||||
|
||||
lasso.move = polygon => {
|
||||
lasso.move = (polygon) => {
|
||||
if (polygon !== lassoPolygon || polygon.length !== lassoPolygon.length) {
|
||||
lasso.reset();
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export default (
|
||||
.brush()
|
||||
.extent([
|
||||
[0, 0],
|
||||
[responsive.width - graphPaddingRight, responsive.height]
|
||||
[responsive.width - graphPaddingRight, responsive.height],
|
||||
])
|
||||
.on("start", handleStartAction)
|
||||
.on("brush", handleDragAction)
|
||||
|
||||
@@ -4,12 +4,12 @@ import { connect } from "react-redux";
|
||||
import * as globals from "../../globals";
|
||||
import Logo from "../framework/logo";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
responsive: state.responsive,
|
||||
datasetTitle: state.config?.displayNames?.dataset ?? "",
|
||||
aboutURL: state.config?.links?.["about-dataset"],
|
||||
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
|
||||
scatterplotYYaccessor: state.controls.scatterplotYYaccessor
|
||||
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
|
||||
}))
|
||||
class LeftSideBar extends React.Component {
|
||||
render() {
|
||||
@@ -35,7 +35,7 @@ class LeftSideBar extends React.Component {
|
||||
width: globals.leftSidebarWidth - paddingToAvoidScrollBar,
|
||||
position: "absolute",
|
||||
backgroundColor: "white",
|
||||
zIndex: 8888
|
||||
zIndex: 8888,
|
||||
/* x y blur spread color */
|
||||
// boxShadow: "-5px -1px 4px 2px rgba(225,225,225,0.4)"
|
||||
}}
|
||||
@@ -49,7 +49,7 @@ class LeftSideBar extends React.Component {
|
||||
fontWeight: "bold",
|
||||
marginLeft: 5,
|
||||
color: globals.logoColor,
|
||||
userSelect: "none"
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
cell
|
||||
@@ -58,7 +58,7 @@ class LeftSideBar extends React.Component {
|
||||
position: "relative",
|
||||
top: 1,
|
||||
fontWeight: 300,
|
||||
fontSize: 24
|
||||
fontSize: 24,
|
||||
}}
|
||||
>
|
||||
×
|
||||
@@ -76,11 +76,17 @@ class LeftSideBar extends React.Component {
|
||||
marginLeft: "7px",
|
||||
height: "1.2em",
|
||||
overflow: "hidden",
|
||||
wordBreak: "break-all"
|
||||
wordBreak: "break-all",
|
||||
}}
|
||||
title={datasetTitle}
|
||||
>
|
||||
{aboutURL ? <a href={aboutURL} target="_blank">{displayTitle}</a> : displayTitle}
|
||||
{aboutURL ? (
|
||||
<a href={aboutURL} target="_blank">
|
||||
{displayTitle}
|
||||
</a>
|
||||
) : (
|
||||
displayTitle
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ class CellSetButton extends React.PureComponent {
|
||||
differential,
|
||||
crossfilter,
|
||||
dispatch,
|
||||
eitherCellSetOneOrTwo
|
||||
eitherCellSetOneOrTwo,
|
||||
} = this.props;
|
||||
|
||||
// Reducer and components assume that value will be null if
|
||||
@@ -25,7 +25,7 @@ class CellSetButton extends React.PureComponent {
|
||||
/* diffexp needs to be cleared before we store a new set */
|
||||
dispatch({
|
||||
type: `store current cell selection as differential set ${eitherCellSetOneOrTwo}`,
|
||||
data: set
|
||||
data: set,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
Popover,
|
||||
NumericInput,
|
||||
Icon,
|
||||
Tooltip
|
||||
Tooltip,
|
||||
} from "@blueprintjs/core";
|
||||
import { tooltipHoverOpenDelay } from "../../globals";
|
||||
|
||||
@@ -21,7 +21,7 @@ function Clip(props) {
|
||||
isClipDisabled,
|
||||
handleClipOnKeyPress,
|
||||
handleClipPercentileMaxValueChange,
|
||||
handleClipPercentileMinValueChange
|
||||
handleClipPercentileMinValueChange,
|
||||
} = props;
|
||||
|
||||
const clipMin =
|
||||
@@ -37,7 +37,7 @@ function Clip(props) {
|
||||
<div
|
||||
className="bp3-button-group"
|
||||
style={{
|
||||
marginRight: 10
|
||||
marginRight: 10,
|
||||
}}
|
||||
>
|
||||
<Popover
|
||||
@@ -52,7 +52,7 @@ function Clip(props) {
|
||||
data-testid="visualization-settings"
|
||||
className={`bp3-button bp3-icon-timeline-bar-chart ${activeClipClass}`}
|
||||
style={{
|
||||
cursor: "pointer"
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -67,7 +67,7 @@ function Clip(props) {
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
flexDirection: "column",
|
||||
padding: 10
|
||||
padding: 10,
|
||||
}}
|
||||
>
|
||||
<div>Clip all continuous values to percentile range</div>
|
||||
@@ -77,7 +77,7 @@ function Clip(props) {
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
paddingTop: 5,
|
||||
paddingBottom: 5
|
||||
paddingBottom: 5,
|
||||
}}
|
||||
>
|
||||
<NumericInput
|
||||
@@ -121,7 +121,7 @@ function Clip(props) {
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
marginRight: 5,
|
||||
marginLeft: 5
|
||||
marginLeft: 5,
|
||||
}}
|
||||
onClick={handleClipCommit}
|
||||
>
|
||||
|
||||
@@ -7,26 +7,26 @@ import {
|
||||
ButtonGroup,
|
||||
AnchorButton,
|
||||
Tooltip,
|
||||
Position
|
||||
Position,
|
||||
} from "@blueprintjs/core";
|
||||
import * as globals from "../../globals";
|
||||
import actions from "../../actions";
|
||||
import CellSetButton from "./cellSetButtons";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
config: state.config,
|
||||
crossfilter: state.crossfilter,
|
||||
differential: state.differential,
|
||||
celllist1: state.differential?.celllist1,
|
||||
celllist2: state.differential?.celllist2,
|
||||
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
||||
diffexpCellcountMax: state.config?.limits?.diffexp_cellcount_max
|
||||
diffexpCellcountMax: state.config?.limits?.diffexp_cellcount_max,
|
||||
}))
|
||||
class DiffexpButtons extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
userDismissedPopover: false
|
||||
userDismissedPopover: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,16 +46,16 @@ class DiffexpButtons extends React.Component {
|
||||
const { dispatch, differential } = this.props;
|
||||
dispatch({
|
||||
type: "clear differential expression",
|
||||
diffExp: differential.diffExp
|
||||
diffExp: differential.diffExp,
|
||||
});
|
||||
dispatch({
|
||||
type: "clear scatterplot"
|
||||
type: "clear scatterplot",
|
||||
});
|
||||
};
|
||||
|
||||
handlePopoverDismiss = () => {
|
||||
this.setState({
|
||||
userDismissedPopover: true
|
||||
userDismissedPopover: true,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -124,7 +124,7 @@ class DiffexpButtons extends React.Component {
|
||||
alignItems: "flex-end",
|
||||
flexDirection: "column",
|
||||
padding: 10,
|
||||
maxWidth: 310
|
||||
maxWidth: 310,
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
|
||||
@@ -7,26 +7,26 @@ import {
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Tooltip,
|
||||
Position
|
||||
Position,
|
||||
} from "@blueprintjs/core";
|
||||
import { connect } from "react-redux";
|
||||
import * as globals from "../../globals";
|
||||
import { World } from "../../util/stateManager";
|
||||
import actions from "../../actions";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
universe: state.universe,
|
||||
world: state.world,
|
||||
layoutChoice: state.layoutChoice,
|
||||
reembedController: state.reembedController,
|
||||
enableReembedding: state.config?.parameters?.["enable-reembedding"] ?? false
|
||||
enableReembedding: state.config?.parameters?.["enable-reembedding"] ?? false,
|
||||
}))
|
||||
class Embedding extends React.PureComponent {
|
||||
handleLayoutChoiceChange = e => {
|
||||
handleLayoutChoiceChange = (e) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({
|
||||
type: "set layout choice",
|
||||
layoutChoice: e.currentTarget.value
|
||||
layoutChoice: e.currentTarget.value,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ class Embedding extends React.PureComponent {
|
||||
world,
|
||||
universe,
|
||||
dispatch,
|
||||
reembedController
|
||||
reembedController,
|
||||
} = this.props;
|
||||
|
||||
if (!enableReembedding) return null;
|
||||
@@ -70,7 +70,7 @@ class Embedding extends React.PureComponent {
|
||||
return (
|
||||
<ButtonGroup
|
||||
style={{
|
||||
marginRight: 10
|
||||
marginRight: 10,
|
||||
}}
|
||||
>
|
||||
<Popover
|
||||
@@ -85,7 +85,7 @@ class Embedding extends React.PureComponent {
|
||||
data-testid="layout-choice"
|
||||
icon="heatmap"
|
||||
style={{
|
||||
cursor: "pointer"
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -98,7 +98,7 @@ class Embedding extends React.PureComponent {
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
flexDirection: "column",
|
||||
padding: 10
|
||||
padding: 10,
|
||||
}}
|
||||
>
|
||||
<RadioGroup
|
||||
@@ -106,7 +106,7 @@ class Embedding extends React.PureComponent {
|
||||
onChange={this.handleLayoutChoiceChange}
|
||||
selectedValue={layoutChoice.current}
|
||||
>
|
||||
{layoutChoice.available.map(name => (
|
||||
{layoutChoice.available.map((name) => (
|
||||
<Radio label={name} value={name} key={name} />
|
||||
))}
|
||||
</RadioGroup>
|
||||
|
||||
@@ -11,7 +11,7 @@ import Subset from "./subset";
|
||||
import UndoRedoReset from "./undoRedo";
|
||||
import DiffexpButtons from "./diffexpButtons";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
universe: state.universe,
|
||||
world: state.world,
|
||||
crossfilter: state.crossfilter,
|
||||
@@ -34,7 +34,7 @@ import DiffexpButtons from "./diffexpButtons";
|
||||
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
||||
showCentroidLabels: state.centroidLabels.showLabels,
|
||||
tosURL: state.config?.parameters?.about_legal_tos,
|
||||
privacyURL: state.config?.parameters?.about_legal_privacy
|
||||
privacyURL: state.config?.parameters?.about_legal_privacy,
|
||||
}))
|
||||
class MenuBar extends React.Component {
|
||||
static isValidDigitKeyEvent(e) {
|
||||
@@ -64,7 +64,7 @@ class MenuBar extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
pendingClipPercentiles: null
|
||||
pendingClipPercentiles: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class MenuBar extends React.Component {
|
||||
return isDisabled;
|
||||
};
|
||||
|
||||
handleClipOnKeyPress = e => {
|
||||
handleClipOnKeyPress = (e) => {
|
||||
/*
|
||||
allow only numbers, plus other critical keys which
|
||||
may be required to make a number
|
||||
@@ -100,7 +100,7 @@ class MenuBar extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
handleClipPercentileMinValueChange = v => {
|
||||
handleClipPercentileMinValueChange = (v) => {
|
||||
/*
|
||||
Ignore anything that isn't a legit number
|
||||
*/
|
||||
@@ -116,11 +116,11 @@ class MenuBar extends React.Component {
|
||||
if (v > 100) v = 100;
|
||||
const clipPercentileMin = Math.round(v); // paranoia
|
||||
this.setState({
|
||||
pendingClipPercentiles: { clipPercentileMin, clipPercentileMax }
|
||||
pendingClipPercentiles: { clipPercentileMin, clipPercentileMax },
|
||||
});
|
||||
};
|
||||
|
||||
handleClipPercentileMaxValueChange = v => {
|
||||
handleClipPercentileMaxValueChange = (v) => {
|
||||
/*
|
||||
Ignore anything that isn't a legit number
|
||||
*/
|
||||
@@ -137,7 +137,7 @@ class MenuBar extends React.Component {
|
||||
const clipPercentileMax = Math.round(v); // paranoia
|
||||
|
||||
this.setState({
|
||||
pendingClipPercentiles: { clipPercentileMin, clipPercentileMax }
|
||||
pendingClipPercentiles: { clipPercentileMin, clipPercentileMax },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -149,14 +149,14 @@ class MenuBar extends React.Component {
|
||||
const max = clipPercentileMax / 100;
|
||||
dispatch({
|
||||
type: "set clip quantiles",
|
||||
clipQuantiles: { min, max }
|
||||
clipQuantiles: { min, max },
|
||||
});
|
||||
};
|
||||
|
||||
handleClipOpening = () => {
|
||||
const { clipPercentileMin, clipPercentileMax } = this.props;
|
||||
this.setState({
|
||||
pendingClipPercentiles: { clipPercentileMin, clipPercentileMax }
|
||||
pendingClipPercentiles: { clipPercentileMin, clipPercentileMax },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -169,7 +169,7 @@ class MenuBar extends React.Component {
|
||||
|
||||
dispatch({
|
||||
type: "show centroid labels for category",
|
||||
showLabels: !showCentroidLabels
|
||||
showLabels: !showCentroidLabels,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -200,7 +200,7 @@ class MenuBar extends React.Component {
|
||||
aboutLink,
|
||||
showCentroidLabels,
|
||||
privacyURL,
|
||||
tosURL
|
||||
tosURL,
|
||||
} = this.props;
|
||||
const { pendingClipPercentiles } = this.state;
|
||||
|
||||
@@ -221,10 +221,10 @@ class MenuBar extends React.Component {
|
||||
position: "fixed",
|
||||
right: globals.leftSidebarWidth + 8,
|
||||
top: 8,
|
||||
display: "flex"
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
{disableDiffexp ? null : <DiffexpButtons/>}
|
||||
{disableDiffexp ? null : <DiffexpButtons />}
|
||||
<Subset
|
||||
subsetPossible={this.subsetPossible()}
|
||||
subsetResetPossible={this.subsetResetPossible()}
|
||||
@@ -251,11 +251,11 @@ class MenuBar extends React.Component {
|
||||
onClick={() => {
|
||||
dispatch({
|
||||
type: "change graph interaction mode",
|
||||
data: "select"
|
||||
data: "select",
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
cursor: "pointer"
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -272,11 +272,11 @@ class MenuBar extends React.Component {
|
||||
onClick={() => {
|
||||
dispatch({
|
||||
type: "change graph interaction mode",
|
||||
data: "zoom"
|
||||
data: "zoom",
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
cursor: "pointer"
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
@@ -294,7 +294,7 @@ class MenuBar extends React.Component {
|
||||
active={showCentroidLabels}
|
||||
intent={showCentroidLabels ? "primary" : "none"}
|
||||
style={{
|
||||
marginRight: 10
|
||||
marginRight: 10,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
@@ -47,16 +47,16 @@ function InformationMenu(props) {
|
||||
}`}
|
||||
/>
|
||||
<MenuItem text="MIT License" />
|
||||
{tosURL ? <MenuItem
|
||||
href={tosURL}
|
||||
target="_blank"
|
||||
text="Terms of Service"
|
||||
/> : null }
|
||||
{privacyURL ? <MenuItem
|
||||
href={privacyURL}
|
||||
target="_blank"
|
||||
text="Privacy Policy"
|
||||
/> : null }
|
||||
{tosURL ? (
|
||||
<MenuItem href={tosURL} target="_blank" text="Terms of Service" />
|
||||
) : null}
|
||||
{privacyURL ? (
|
||||
<MenuItem
|
||||
href={privacyURL}
|
||||
target="_blank"
|
||||
text="Privacy Policy"
|
||||
/>
|
||||
) : null}
|
||||
</Menu>
|
||||
}
|
||||
position={Position.BOTTOM_RIGHT}
|
||||
@@ -65,7 +65,7 @@ function InformationMenu(props) {
|
||||
type="button"
|
||||
className="bp3-button bp3-icon-info-sign"
|
||||
style={{
|
||||
cursor: "pointer"
|
||||
cursor: "pointer",
|
||||
}}
|
||||
/>
|
||||
</Popover>
|
||||
|
||||
@@ -7,7 +7,7 @@ function Subset(props) {
|
||||
subsetPossible,
|
||||
subsetResetPossible,
|
||||
handleSubset,
|
||||
handleSubsetReset
|
||||
handleSubsetReset,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,11 +4,7 @@ import { AnchorButton, Tooltip } from "@blueprintjs/core";
|
||||
import { tooltipHoverOpenDelay } from "../../globals";
|
||||
|
||||
function InformationMenu(props) {
|
||||
const {
|
||||
undoDisabled,
|
||||
redoDisabled,
|
||||
dispatch
|
||||
} = props;
|
||||
const { undoDisabled, redoDisabled, dispatch } = props;
|
||||
return (
|
||||
<div style={{ marginRight: 10 }} className="bp3-button-group">
|
||||
<Tooltip
|
||||
@@ -24,7 +20,7 @@ function InformationMenu(props) {
|
||||
dispatch({ type: "@@undoable/undo" });
|
||||
}}
|
||||
style={{
|
||||
cursor: "pointer"
|
||||
cursor: "pointer",
|
||||
}}
|
||||
data-testid="undo"
|
||||
/>
|
||||
@@ -42,7 +38,7 @@ function InformationMenu(props) {
|
||||
dispatch({ type: "@@undoable/redo" });
|
||||
}}
|
||||
style={{
|
||||
cursor: "pointer"
|
||||
cursor: "pointer",
|
||||
}}
|
||||
data-testid="redo"
|
||||
/>
|
||||
|
||||
@@ -5,10 +5,10 @@ import Continuous from "../continuous/continuous";
|
||||
import GeneExpression from "../geneExpression";
|
||||
import * as globals from "../../globals";
|
||||
|
||||
@connect(state => ({
|
||||
@connect((state) => ({
|
||||
responsive: state.responsive,
|
||||
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
|
||||
scatterplotYYaccessor: state.controls.scatterplotYYaccessor
|
||||
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
|
||||
}))
|
||||
class RightSidebar extends React.Component {
|
||||
render() {
|
||||
@@ -21,7 +21,7 @@ class RightSidebar extends React.Component {
|
||||
right: 0,
|
||||
backgroundColor: "white",
|
||||
/* x y blur spread color */
|
||||
borderLeft: `1px solid ${globals.lightGrey}`
|
||||
borderLeft: `1px solid ${globals.lightGrey}`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
@@ -29,7 +29,7 @@ class RightSidebar extends React.Component {
|
||||
height: responsive.height,
|
||||
width: globals.leftSidebarWidth,
|
||||
overflowY: "auto",
|
||||
overflowX: "hidden"
|
||||
overflowX: "hidden",
|
||||
}}
|
||||
>
|
||||
<GeneExpression />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { glPointFlags, glPointSize } from "../../util/glHelpers";
|
||||
|
||||
export default function(regl) {
|
||||
export default function (regl) {
|
||||
return regl({
|
||||
vert: `
|
||||
precision mediump float;
|
||||
@@ -52,17 +52,17 @@ export default function(regl) {
|
||||
attributes: {
|
||||
position: regl.prop("position"),
|
||||
color: regl.prop("color"),
|
||||
flag: regl.prop("flag")
|
||||
flag: regl.prop("flag"),
|
||||
},
|
||||
|
||||
uniforms: {
|
||||
projection: regl.prop("projection"),
|
||||
nPoints: regl.prop("nPoints"),
|
||||
minViewportDimension: regl.prop("minViewportDimension")
|
||||
minViewportDimension: regl.prop("minViewportDimension"),
|
||||
},
|
||||
|
||||
count: regl.prop("count"),
|
||||
|
||||
primitive: "points"
|
||||
primitive: "points",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ function createProjectionTF(viewportWidth, viewportHeight) {
|
||||
return mat3.projection(m, viewportWidth, viewportHeight);
|
||||
}
|
||||
|
||||
@connect(state => {
|
||||
@connect((state) => {
|
||||
const { world, crossfilter, universe } = state;
|
||||
const { scatterplotXXaccessor, scatterplotYYaccessor } = state.controls;
|
||||
const expressionX = scatterplotXXaccessor
|
||||
@@ -54,7 +54,7 @@ function createProjectionTF(viewportWidth, viewportHeight) {
|
||||
|
||||
crossfilter,
|
||||
|
||||
responsive: state.responsive
|
||||
responsive: state.responsive,
|
||||
};
|
||||
})
|
||||
class Scatterplot extends React.PureComponent {
|
||||
@@ -67,7 +67,7 @@ class Scatterplot extends React.PureComponent {
|
||||
return positions;
|
||||
});
|
||||
|
||||
computePointColors = memoize(rgb => {
|
||||
computePointColors = memoize((rgb) => {
|
||||
/*
|
||||
compute webgl colors for each point
|
||||
*/
|
||||
@@ -135,11 +135,11 @@ class Scatterplot extends React.PureComponent {
|
||||
colors: null,
|
||||
flags: null,
|
||||
xScale: null,
|
||||
yScale: null
|
||||
yScale: null,
|
||||
};
|
||||
this.state = {
|
||||
svg: null,
|
||||
minimized: null
|
||||
minimized: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ class Scatterplot extends React.PureComponent {
|
||||
colorBuffer,
|
||||
svg,
|
||||
drawPoints,
|
||||
projectionTF
|
||||
projectionTF,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ class Scatterplot extends React.PureComponent {
|
||||
expressionY,
|
||||
colorRGB,
|
||||
colorAccessor,
|
||||
pointDilation
|
||||
pointDilation,
|
||||
} = this.props;
|
||||
const {
|
||||
regl,
|
||||
@@ -207,7 +207,7 @@ class Scatterplot extends React.PureComponent {
|
||||
flagBuffer,
|
||||
svg,
|
||||
drawPoints,
|
||||
projectionTF
|
||||
projectionTF,
|
||||
} = this.state;
|
||||
|
||||
if (
|
||||
@@ -284,7 +284,7 @@ class Scatterplot extends React.PureComponent {
|
||||
|
||||
return {
|
||||
xScale,
|
||||
yScale
|
||||
yScale,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -294,15 +294,9 @@ class Scatterplot extends React.PureComponent {
|
||||
|
||||
// the axes are much cleaner and easier now. No need to rotate and orient
|
||||
// the axis, just call axisBottom, axisLeft etc.
|
||||
const xAxis = d3
|
||||
.axisBottom()
|
||||
.ticks(7)
|
||||
.scale(xScale);
|
||||
const xAxis = d3.axisBottom().ticks(7).scale(xScale);
|
||||
|
||||
const yAxis = d3
|
||||
.axisLeft()
|
||||
.ticks(7)
|
||||
.scale(yScale);
|
||||
const yAxis = d3.axisLeft().ticks(7).scale(yScale);
|
||||
|
||||
// adding axes is also simpler now, just translate x-axis to (0,height)
|
||||
// and it's alread defined to be a bottom axis.
|
||||
@@ -356,7 +350,7 @@ class Scatterplot extends React.PureComponent {
|
||||
regl.poll();
|
||||
regl.clear({
|
||||
depth: 1,
|
||||
color: [1, 1, 1, 1]
|
||||
color: [1, 1, 1, 1],
|
||||
});
|
||||
drawPoints({
|
||||
flag: flagBuffer,
|
||||
@@ -368,7 +362,7 @@ class Scatterplot extends React.PureComponent {
|
||||
minViewportDimension: Math.min(
|
||||
cvWidth - globals.leftSidebarWidth || width,
|
||||
cvHeight || height
|
||||
)
|
||||
),
|
||||
});
|
||||
regl._gl.flush();
|
||||
}
|
||||
@@ -387,7 +381,7 @@ class Scatterplot extends React.PureComponent {
|
||||
padding: "0px 20px 20px 0px",
|
||||
backgroundColor: "white",
|
||||
/* x y blur spread color */
|
||||
boxShadow: "0px 0px 6px 2px rgba(153,153,153,0.4)"
|
||||
boxShadow: "0px 0px 6px 2px rgba(153,153,153,0.4)",
|
||||
}}
|
||||
id="scatterplot_wrapper"
|
||||
>
|
||||
@@ -395,7 +389,7 @@ class Scatterplot extends React.PureComponent {
|
||||
style={{
|
||||
position: "absolute",
|
||||
right: 5,
|
||||
top: 5
|
||||
top: 5,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
@@ -413,7 +407,7 @@ class Scatterplot extends React.PureComponent {
|
||||
data-testid="clear-scatterplot"
|
||||
onClick={() =>
|
||||
dispatch({
|
||||
type: "clear scatterplot"
|
||||
type: "clear scatterplot",
|
||||
})
|
||||
}
|
||||
>
|
||||
@@ -425,7 +419,7 @@ class Scatterplot extends React.PureComponent {
|
||||
id="scatterplot"
|
||||
style={{
|
||||
width: `${width + margin.left + margin.right}px`,
|
||||
height: `${height + margin.top + margin.bottom}px`
|
||||
height: `${height + margin.top + margin.bottom}px`,
|
||||
}}
|
||||
>
|
||||
<canvas
|
||||
@@ -434,9 +428,9 @@ class Scatterplot extends React.PureComponent {
|
||||
data-testid="scatterplot"
|
||||
style={{
|
||||
marginLeft: margin.left,
|
||||
marginTop: margin.top
|
||||
marginTop: margin.top,
|
||||
}}
|
||||
ref={canvas => {
|
||||
ref={(canvas) => {
|
||||
this.reglCanvas = canvas;
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -19,7 +19,7 @@ const setupScatterplot = (width, height, margin) => {
|
||||
.attr("transform", `translate(${margin.left},${margin.top})`);
|
||||
|
||||
return {
|
||||
svg
|
||||
svg,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user