mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-25 20:18:12 +08:00
Viewport fills entire screen (#430)
* full pane webgl and svg * fixes for full pane selection and centering * force graph remount, clear brush state
This commit is contained in:
@@ -297,6 +297,9 @@ const resetInterface = () => (dispatch, getState) => {
|
||||
type: "reset World to eq Universe",
|
||||
universe
|
||||
});
|
||||
dispatch({
|
||||
type: "increment graph render counter"
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -11,7 +11,8 @@ import actions from "../actions";
|
||||
|
||||
@connect(state => ({
|
||||
loading: state.controls.loading,
|
||||
error: state.controls.error
|
||||
error: state.controls.error,
|
||||
graphRenderCounter: state.controls.graphRenderCounter
|
||||
}))
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -54,7 +55,7 @@ class App extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { loading } = this.props;
|
||||
const { loading, error, graphRenderCounter } = this.props;
|
||||
return (
|
||||
<Container>
|
||||
<Helmet title="cellxgene" />
|
||||
@@ -79,10 +80,8 @@ class App extends React.Component {
|
||||
marginLeft: 350 /* but responsive */
|
||||
}}
|
||||
>
|
||||
{loading ? null : <Graph />}
|
||||
|
||||
{loading ? null : <Graph key={graphRenderCounter} />}
|
||||
<Legend />
|
||||
{}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function(regl) {
|
||||
uniforms: {
|
||||
distance: regl.prop("distance"),
|
||||
view: regl.prop("view"),
|
||||
projection: () => mat4.perspective([], Math.PI / 2, 1, 0.01, 1000)
|
||||
projection: ({viewportWidth, viewportHeight}) => mat4.perspective([], Math.PI / 2, viewportWidth / viewportHeight, 0.01, 1000)
|
||||
},
|
||||
|
||||
count: regl.prop("count"),
|
||||
|
||||
@@ -6,8 +6,7 @@ import { connect } from "react-redux";
|
||||
import mat4 from "gl-mat4";
|
||||
import _regl from "regl";
|
||||
import { Button, AnchorButton, Tooltip } from "@blueprintjs/core";
|
||||
import { worldEqUniverse } from "../../util/stateManager/world";
|
||||
|
||||
import * as globals from "../../globals";
|
||||
import setupSVGandBrushElements from "./setupSVGandBrush";
|
||||
import actions from "../../actions";
|
||||
import _camera from "../../util/camera";
|
||||
@@ -30,9 +29,9 @@ class Graph extends React.Component {
|
||||
super(props);
|
||||
this.count = 0;
|
||||
this.inverse = mat4.identity([]);
|
||||
this.graphPaddingTop = 100;
|
||||
this.graphPaddingTop = 0;
|
||||
this.graphPaddingBottom = 45;
|
||||
this.graphPaddingRight = 10;
|
||||
this.graphPaddingRight = globals.leftSidebarWidth;
|
||||
this.renderCache = {
|
||||
positions: null,
|
||||
colors: null
|
||||
@@ -126,18 +125,24 @@ class Graph extends React.Component {
|
||||
const glScaleX = scaleLinear([0, 1], [-1, 1]);
|
||||
const glScaleY = scaleLinear([0, 1], [1, -1]);
|
||||
|
||||
const offset = [d3.mean(obsLayout.X) - 0.5, d3.mean(obsLayout.Y) - 0.5];
|
||||
|
||||
for (
|
||||
let i = 0, { positions } = this.renderCache;
|
||||
i < cellCount;
|
||||
i += 1
|
||||
) {
|
||||
positions[2 * i] = glScaleX(obsLayout.X[i]);
|
||||
positions[2 * i + 1] = glScaleY(obsLayout.Y[i]);
|
||||
positions[2 * i] = glScaleX(obsLayout.X[i] - offset[0]);
|
||||
positions[2 * i + 1] = glScaleY(obsLayout.Y[i] - offset[1]);
|
||||
}
|
||||
pointBuffer({
|
||||
data: this.renderCache.positions,
|
||||
dimension: 2
|
||||
});
|
||||
|
||||
this.setState({
|
||||
offset
|
||||
});
|
||||
}
|
||||
|
||||
// Colors for each point - a cached value that only changes when
|
||||
@@ -196,7 +201,7 @@ class Graph extends React.Component {
|
||||
this.handleBrushSelectAction.bind(this),
|
||||
this.handleBrushDeselectAction.bind(this),
|
||||
responsive,
|
||||
this.graphPaddingTop
|
||||
this.graphPaddingRight
|
||||
);
|
||||
this.setState({ svg: newSvg, brush });
|
||||
}
|
||||
@@ -251,7 +256,7 @@ class Graph extends React.Component {
|
||||
an event on procedural deselect because it is move: null
|
||||
*/
|
||||
|
||||
const { camera } = this.state;
|
||||
const { camera, offset } = this.state;
|
||||
const { dispatch, responsive } = this.props;
|
||||
|
||||
if (d3.event.sourceEvent !== null) {
|
||||
@@ -262,6 +267,7 @@ class Graph extends React.Component {
|
||||
https://bl.ocks.org/EfratVil/0e542f5fc426065dd1d4b6daaa345a9f
|
||||
*/
|
||||
const s = d3.event.selection;
|
||||
const gl = this.state.regl._gl;
|
||||
/*
|
||||
event describing brush position:
|
||||
@-------|
|
||||
@@ -270,19 +276,23 @@ class Graph extends React.Component {
|
||||
|-------@
|
||||
*/
|
||||
|
||||
// get aspect ratio
|
||||
const aspect = gl.drawingBufferWidth / gl.drawingBufferHeight;
|
||||
|
||||
// compute inverse view matrix
|
||||
const inverse = mat4.invert([], camera.view());
|
||||
|
||||
// transform screen coordinates -> cell coordinates
|
||||
const invert = pin => {
|
||||
const x = (2 * pin[0]) / (responsive.height - this.graphPaddingTop) - 1;
|
||||
const x =
|
||||
(2 * pin[0]) / (responsive.width - this.graphPaddingRight) - 1;
|
||||
const y =
|
||||
2 * (1 - pin[1] / (responsive.height - this.graphPaddingTop)) - 1;
|
||||
const pout = [
|
||||
x * inverse[14] + inverse[12],
|
||||
x * inverse[14] * aspect + inverse[12],
|
||||
y * inverse[14] + inverse[13]
|
||||
];
|
||||
return [(pout[0] + 1) / 2, (pout[1] + 1) / 2];
|
||||
return [(pout[0] + 1) / 2 + offset[0], (pout[1] + 1) / 2 + offset[1]];
|
||||
};
|
||||
|
||||
const brushCoords = {
|
||||
@@ -366,6 +376,7 @@ class Graph extends React.Component {
|
||||
style={{ marginRight: 10 }}
|
||||
onClick={() => {
|
||||
dispatch(actions.regraph());
|
||||
dispatch({ type: "increment graph render counter" });
|
||||
}}
|
||||
>
|
||||
subset to current selection
|
||||
@@ -421,12 +432,10 @@ class Graph extends React.Component {
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
marginRight: 50,
|
||||
marginTop: 50,
|
||||
zIndex: -9999,
|
||||
position: "fixed",
|
||||
right: this.graphPaddingRight,
|
||||
bottom: this.graphPaddingBottom
|
||||
top: 0,
|
||||
right: 0
|
||||
}}
|
||||
>
|
||||
<div
|
||||
@@ -437,7 +446,7 @@ class Graph extends React.Component {
|
||||
/>
|
||||
<div style={{ padding: 0, margin: 0 }}>
|
||||
<canvas
|
||||
width={responsive.height - this.graphPaddingTop}
|
||||
width={responsive.width - this.graphPaddingRight}
|
||||
height={responsive.height - this.graphPaddingTop}
|
||||
ref={canvas => {
|
||||
this.reglCanvas = canvas;
|
||||
|
||||
@@ -12,22 +12,18 @@ export default (
|
||||
handleBrushSelectAction,
|
||||
handleBrushDeselectAction,
|
||||
responsive,
|
||||
graphPaddingTop
|
||||
graphPaddingRight
|
||||
) => {
|
||||
const side = responsive.height - graphPaddingTop;
|
||||
const svg = d3
|
||||
.select("#graphAttachPoint")
|
||||
.append("svg")
|
||||
.attr("width", side)
|
||||
.attr("height", side)
|
||||
.attr("width", responsive.width - graphPaddingRight)
|
||||
.attr("height", responsive.height)
|
||||
.attr("class", `${styles.graphSVG}`);
|
||||
|
||||
const brush = d3
|
||||
.brush()
|
||||
.extent([
|
||||
[0, 0],
|
||||
[responsive.height - graphPaddingTop, responsive.height - graphPaddingTop]
|
||||
])
|
||||
.extent([[0, 0], [responsive.width - graphPaddingRight, responsive.height]])
|
||||
.on("brush", handleBrushSelectAction)
|
||||
.on("end", handleBrushDeselectAction);
|
||||
|
||||
|
||||
Vendored
+8
-1
@@ -54,6 +54,7 @@ const Controls = (
|
||||
scatterplotXXaccessor: null, // just easier to read
|
||||
scatterplotYYaccessor: null,
|
||||
axesHaveBeenDrawn: false,
|
||||
graphRenderCounter: 0 /* integer as <Component key={graphRenderCounter} - a change in key forces a remount */,
|
||||
__storedStateForCelllist1__: null /* will need procedural control of brush ie., brush.extent https://bl.ocks.org/micahstubbs/3cda05ca68cba260cb81 */,
|
||||
__storedStateForCelllist2__: null
|
||||
},
|
||||
@@ -410,7 +411,13 @@ const Controls = (
|
||||
...state,
|
||||
opacityForDeselectedCells: action.data
|
||||
};
|
||||
|
||||
case "increment graph render counter": {
|
||||
const c = state.graphRenderCounter + 1;
|
||||
return {
|
||||
...state,
|
||||
graphRenderCounter: c
|
||||
};
|
||||
}
|
||||
/*******************************
|
||||
Categorical metadata
|
||||
*******************************/
|
||||
|
||||
Reference in New Issue
Block a user