mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-20 03:18:12 +08:00
* mocks for redux refactor - for discussion * more API design on redux refactor * add new reuqired dependencies for build * change babel target to use modern browser * remove dead code * remove dead code - joy plots * checkpoint on redux refactoring * checkpoint on redux refactoring * fix mistaken rebase conflict resolution * dead code removal; add name to dataframe backmap * rename dataframe to universe * update eslint config to more closely match prettier * lint * more eslint updates to match prettier * additional config to make eslint match prettier * add expression data to Universe/World * remove obsolete reducers * lint fixes * more eslint cleanup * lint * lint * fix but in countAllOnes when dimensions gt 1 * lint; do not display name metadata field * lint; colors refactor * lint; colors refactor * update comments * first cut at regraph and reset * enable object-curly-braces consistent mode * lint, handle regraph with no selection * fix expression scatterplot bugs * fix regression legend display * add expression data cache * remove console logging * reset cell color on regraph/reset * remove obsolete server URLs * rename UniverseV01 to Universe_REST_API_v01 * add additional comments on the varDataCache * merge universe reducer into controls reducer; simplify initialization-related actions * use spread operator * fix erroneous comment * convert universe and world state to plain objects, and functionalize supporting code (remove ES6 classes) * use spread operator * lint * improve variable names * rename obsCrossfilter to crossfilter and obsDimensionMap to dimensionMap * rename controls2 to controls
This commit is contained in:
@@ -24,10 +24,12 @@ import FaSave from "react-icons/lib/fa/download";
|
||||
|
||||
@connect(state => {
|
||||
return {
|
||||
cellsMetadata: state.controls.cellsMetadata,
|
||||
opacityForDeselectedCells: state.controls.opacityForDeselectedCells,
|
||||
world: state.controls.world,
|
||||
crossfilter: state.controls.crossfilter,
|
||||
responsive: state.responsive,
|
||||
crossfilter: state.controls.crossfilter
|
||||
colorRGB: _.get(state.controls, "colorRGB", null),
|
||||
opacityForDeselectedCells: state.controls.opacityForDeselectedCells,
|
||||
selectionUpdate: _.get(state.controls, "crossfilter.updateTime", null)
|
||||
};
|
||||
})
|
||||
class Graph extends React.Component {
|
||||
@@ -43,13 +45,12 @@ class Graph extends React.Component {
|
||||
colors: null
|
||||
};
|
||||
this.state = {
|
||||
drawn: false,
|
||||
svg: null,
|
||||
ctx: null,
|
||||
brush: null,
|
||||
mode: "brush"
|
||||
};
|
||||
}
|
||||
|
||||
reglDraw(regl, drawPoints, sizeBuffer, colorBuffer, pointBuffer, camera) {
|
||||
regl.clear({
|
||||
depth: 1,
|
||||
@@ -64,6 +65,7 @@ class Graph extends React.Component {
|
||||
view: camera.view()
|
||||
});
|
||||
}
|
||||
|
||||
restartReglLoop() {
|
||||
const reglRender = this.state.regl.frame(() => {
|
||||
this.reglDraw(
|
||||
@@ -83,6 +85,7 @@ class Graph extends React.Component {
|
||||
reglRender
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// setup canvas and camera
|
||||
const camera = _camera(this.reglCanvas, { scale: true, rotate: false });
|
||||
@@ -120,7 +123,16 @@ class Graph extends React.Component {
|
||||
reglRender
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const {
|
||||
world,
|
||||
crossfilter,
|
||||
selectionUpdate,
|
||||
colorRGB,
|
||||
responsive
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
this.state.reglRender &&
|
||||
this.reglRenderState === "rendering" &&
|
||||
@@ -130,25 +142,22 @@ class Graph extends React.Component {
|
||||
this.reglRenderState = "paused";
|
||||
}
|
||||
|
||||
if (this.state.regl && this.props.crossfilter) {
|
||||
if (this.state.regl && world) {
|
||||
/* update the regl state */
|
||||
const crossfilter = this.props.crossfilter.cells;
|
||||
const cells = crossfilter.all();
|
||||
const cellCount = cells.length;
|
||||
const obsLayout = world.obsLayout;
|
||||
const cellCount = crossfilter.size();
|
||||
|
||||
// X/Y positions for each point - a cached value that only
|
||||
// changes if we have loaded entirely new cell data
|
||||
//
|
||||
if (
|
||||
!this.renderCache.positions ||
|
||||
this.props.crossfilter.cells != prevProps.crossfilter.cells
|
||||
selectionUpdate != prevProps.selectionUpdate
|
||||
) {
|
||||
if (!this.renderCache.positions)
|
||||
this.renderCache.positions = new Float32Array(2 * cellCount);
|
||||
|
||||
// d3.scaleLinear().domain([0,1]).range([-1,1])
|
||||
const glScaleX = scaleLinear([0, 1], [-1, 1]);
|
||||
// d3.scaleLinear().domain([0,1]).range([1,-1])
|
||||
const glScaleY = scaleLinear([0, 1], [1, -1]);
|
||||
|
||||
for (
|
||||
@@ -156,8 +165,8 @@ class Graph extends React.Component {
|
||||
i < cellCount;
|
||||
i++
|
||||
) {
|
||||
positions[2 * i] = glScaleX(cells[i].__x__);
|
||||
positions[2 * i + 1] = glScaleY(cells[i].__y__);
|
||||
positions[2 * i] = glScaleX(obsLayout.X[i]);
|
||||
positions[2 * i + 1] = glScaleY(obsLayout.Y[i]);
|
||||
}
|
||||
this.state.pointBuffer({
|
||||
data: this.renderCache.positions,
|
||||
@@ -171,14 +180,12 @@ class Graph extends React.Component {
|
||||
// could have changed for some other reason, but for now color is
|
||||
// the only metadata that changes client-side. If this is problematic,
|
||||
// we could add some sort of color-specific indicator to the app state.
|
||||
if (
|
||||
!this.renderCache.colors ||
|
||||
this.props.cellsMetadata != prevProps.cellsMetadata
|
||||
) {
|
||||
if (!this.renderCache.colors || colorRGB != prevProps.colorRGB) {
|
||||
const rgb = colorRGB;
|
||||
if (!this.renderCache.colors)
|
||||
this.renderCache.colors = new Float32Array(3 * cellCount);
|
||||
for (let i = 0, colors = this.renderCache.colors; i < cellCount; i++) {
|
||||
colors.set(cells[i].__colorRGB__, 3 * i);
|
||||
this.renderCache.colors = new Float32Array(3 * rgb.length);
|
||||
for (let i = 0, colors = this.renderCache.colors; i < rgb.length; i++) {
|
||||
colors.set(rgb[i], 3 * i);
|
||||
}
|
||||
this.state.colorBuffer({ data: this.renderCache.colors, dimension: 3 });
|
||||
}
|
||||
@@ -188,12 +195,8 @@ class Graph extends React.Component {
|
||||
// most property upates are due to changes driving a crossfilter
|
||||
// selection set change.
|
||||
//
|
||||
if (
|
||||
!this.renderCache.sizes ||
|
||||
this.props.crossfilter.cells != prevProps.crossfilter.cells
|
||||
) {
|
||||
if (!this.renderCache.sizes)
|
||||
this.renderCache.sizes = new Float32Array(cellCount);
|
||||
}
|
||||
crossfilter.fillByIsFiltered(this.renderCache.sizes, 4, 0.2);
|
||||
this.state.sizeBuffer({ data: this.renderCache.sizes, dimension: 1 });
|
||||
|
||||
@@ -211,12 +214,10 @@ class Graph extends React.Component {
|
||||
}
|
||||
|
||||
if (
|
||||
prevProps.responsive.height !== this.props.responsive.height ||
|
||||
prevProps.responsive.width !== this.props.responsive.width ||
|
||||
prevProps.responsive.height !== responsive.height ||
|
||||
prevProps.responsive.width !== responsive.width ||
|
||||
/* first time */
|
||||
(this.props.responsive.height &&
|
||||
this.props.responsive.width &&
|
||||
!this.state.svg)
|
||||
(responsive.height && responsive.width && !this.state.svg)
|
||||
) {
|
||||
/* clear out whatever was on the div, even if nothing, but usually the brushes etc */
|
||||
d3.select("#graphAttachPoint")
|
||||
@@ -225,12 +226,13 @@ class Graph extends React.Component {
|
||||
const { svg, brush, brushContainer } = setupSVGandBrushElements(
|
||||
this.handleBrushSelectAction.bind(this),
|
||||
this.handleBrushDeselectAction.bind(this),
|
||||
this.props.responsive,
|
||||
responsive,
|
||||
this.graphPaddingTop
|
||||
);
|
||||
this.setState({ svg, brush, brushContainer });
|
||||
}
|
||||
}
|
||||
|
||||
handleBrushSelectAction() {
|
||||
/* This conditional handles procedural brush deselect. Brush emits an event on procedural deselect because it is move: null */
|
||||
if (d3.event.sourceEvent !== null) {
|
||||
@@ -280,6 +282,7 @@ class Graph extends React.Component {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleBrushDeselectAction() {
|
||||
if (d3.event && !d3.event.selection) {
|
||||
this.props.dispatch({
|
||||
@@ -295,6 +298,7 @@ class Graph extends React.Component {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleOpacityRangeChange(e) {
|
||||
this.props.dispatch({
|
||||
type: "change opacity deselected cells in 2d graph background",
|
||||
|
||||
Reference in New Issue
Block a user