mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-06 03:28:13 +08:00
Add frontend
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
export default function drawSpatialImageRegl(regl) {
|
||||||
|
return regl({
|
||||||
|
frag: `
|
||||||
|
precision mediump float;
|
||||||
|
uniform sampler2D texture;
|
||||||
|
varying vec2 uv;
|
||||||
|
void main () {
|
||||||
|
gl_FragColor = texture2D(texture, uv);
|
||||||
|
}`,
|
||||||
|
|
||||||
|
vert: `
|
||||||
|
precision mediump float;
|
||||||
|
attribute vec2 position;
|
||||||
|
varying vec2 uv;
|
||||||
|
const float zMiddle = 0.;
|
||||||
|
uniform mat3 projView;
|
||||||
|
|
||||||
|
vec2 norm(vec2 position) {
|
||||||
|
return ((position - 0.5) * 2.0) * vec2(1., -1.);
|
||||||
|
}
|
||||||
|
void main() {
|
||||||
|
uv = position;
|
||||||
|
vec3 xy = projView * vec3(norm(position), 1.);
|
||||||
|
gl_Position = vec4(xy.xy, 0, 1.);
|
||||||
|
}`,
|
||||||
|
|
||||||
|
attributes: {
|
||||||
|
position: [-1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1],
|
||||||
|
},
|
||||||
|
|
||||||
|
uniforms: {
|
||||||
|
projView: regl.prop("projView"),
|
||||||
|
texture: regl.prop("spatialImageAsTexture"),
|
||||||
|
},
|
||||||
|
|
||||||
|
count: 6,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
createColorTable,
|
createColorTable,
|
||||||
createColorQuery,
|
createColorQuery,
|
||||||
} from "../../util/stateManager/colorHelpers";
|
} from "../../util/stateManager/colorHelpers";
|
||||||
|
import _drawSpatialImage from "./drawSpatialImageRegl";
|
||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
|
|
||||||
import GraphOverlayLayer from "./overlays/graphOverlayLayer";
|
import GraphOverlayLayer from "./overlays/graphOverlayLayer";
|
||||||
@@ -87,6 +88,7 @@ class Graph extends React.Component {
|
|||||||
const camera = _camera(canvas);
|
const camera = _camera(canvas);
|
||||||
const regl = _regl(canvas);
|
const regl = _regl(canvas);
|
||||||
const drawPoints = _drawPoints(regl);
|
const drawPoints = _drawPoints(regl);
|
||||||
|
const drawSpatialImage = _drawSpatialImage(regl);
|
||||||
|
|
||||||
// preallocate webgl buffers
|
// preallocate webgl buffers
|
||||||
const pointBuffer = regl.buffer();
|
const pointBuffer = regl.buffer();
|
||||||
@@ -100,6 +102,7 @@ class Graph extends React.Component {
|
|||||||
pointBuffer,
|
pointBuffer,
|
||||||
colorBuffer,
|
colorBuffer,
|
||||||
flagBuffer,
|
flagBuffer,
|
||||||
|
drawSpatialImage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,6 +235,7 @@ class Graph extends React.Component {
|
|||||||
pointBuffer: null,
|
pointBuffer: null,
|
||||||
colorBuffer: null,
|
colorBuffer: null,
|
||||||
flagBuffer: null,
|
flagBuffer: null,
|
||||||
|
drawSpatialImage: null,
|
||||||
|
|
||||||
// component rendering derived state - these must stay synchronized
|
// component rendering derived state - these must stay synchronized
|
||||||
// with the reducer state they were generated from.
|
// with the reducer state they were generated from.
|
||||||
@@ -317,7 +321,10 @@ class Graph extends React.Component {
|
|||||||
if (e.type !== "wheel") e.preventDefault();
|
if (e.type !== "wheel") e.preventDefault();
|
||||||
if (camera.handleEvent(e, projectionTF)) {
|
if (camera.handleEvent(e, projectionTF)) {
|
||||||
this.renderCanvas();
|
this.renderCanvas();
|
||||||
this.setState((state) => ({ ...state, updateOverlay: !state.updateOverlay }));
|
this.setState((state) => ({
|
||||||
|
...state,
|
||||||
|
updateOverlay: !state.updateOverlay,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -509,6 +516,13 @@ class Graph extends React.Component {
|
|||||||
return { toolSVG: newToolSVG, tool, container };
|
return { toolSVG: newToolSVG, tool, container };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
loadTextureFromUrl = (src) => new Promise((resolve, reject) => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => resolve(img);
|
||||||
|
img.onerror = reject;
|
||||||
|
img.src = src;
|
||||||
|
});
|
||||||
|
|
||||||
fetchAsyncProps = async (props) => {
|
fetchAsyncProps = async (props) => {
|
||||||
const {
|
const {
|
||||||
annoMatrix,
|
annoMatrix,
|
||||||
@@ -551,6 +565,10 @@ class Graph extends React.Component {
|
|||||||
pointDilationLabel
|
pointDilationLabel
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.spatialImage = await this.loadTextureFromUrl(
|
||||||
|
"/api/v0.2/spatial/image"
|
||||||
|
);
|
||||||
|
|
||||||
const { width, height } = viewport;
|
const { width, height } = viewport;
|
||||||
return {
|
return {
|
||||||
positions,
|
positions,
|
||||||
@@ -721,6 +739,7 @@ class Graph extends React.Component {
|
|||||||
flagBuffer,
|
flagBuffer,
|
||||||
camera,
|
camera,
|
||||||
projectionTF,
|
projectionTF,
|
||||||
|
drawSpatialImage,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
this.renderPoints(
|
this.renderPoints(
|
||||||
regl,
|
regl,
|
||||||
@@ -729,7 +748,8 @@ class Graph extends React.Component {
|
|||||||
pointBuffer,
|
pointBuffer,
|
||||||
flagBuffer,
|
flagBuffer,
|
||||||
camera,
|
camera,
|
||||||
projectionTF
|
projectionTF,
|
||||||
|
drawSpatialImage
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -797,7 +817,8 @@ class Graph extends React.Component {
|
|||||||
pointBuffer,
|
pointBuffer,
|
||||||
flagBuffer,
|
flagBuffer,
|
||||||
camera,
|
camera,
|
||||||
projectionTF
|
projectionTF,
|
||||||
|
drawSpatialImage
|
||||||
) {
|
) {
|
||||||
const { annoMatrix } = this.props;
|
const { annoMatrix } = this.props;
|
||||||
if (!this.reglCanvas || !annoMatrix) return;
|
if (!this.reglCanvas || !annoMatrix) return;
|
||||||
@@ -809,7 +830,7 @@ class Graph extends React.Component {
|
|||||||
regl.poll();
|
regl.poll();
|
||||||
regl.clear({
|
regl.clear({
|
||||||
depth: 1,
|
depth: 1,
|
||||||
color: [1, 1, 1, 1],
|
color: [0, 0, 0, 0],
|
||||||
});
|
});
|
||||||
drawPoints({
|
drawPoints({
|
||||||
distance: camera.distance(),
|
distance: camera.distance(),
|
||||||
@@ -821,6 +842,12 @@ class Graph extends React.Component {
|
|||||||
nPoints: schema.dataframe.nObs,
|
nPoints: schema.dataframe.nObs,
|
||||||
minViewportDimension: Math.min(width, height),
|
minViewportDimension: Math.min(width, height),
|
||||||
});
|
});
|
||||||
|
drawSpatialImage({
|
||||||
|
projView,
|
||||||
|
spatialImageAsTexture: regl.texture({
|
||||||
|
data: this.spatialImage,
|
||||||
|
}),
|
||||||
|
});
|
||||||
regl._gl.flush();
|
regl._gl.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -951,32 +978,29 @@ const ErrorLoading = ({ displayName, error, width, height }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const StillLoading = ({ displayName, width, height }) =>
|
const StillLoading = ({ displayName, width, height }) => (
|
||||||
/*
|
/*
|
||||||
Render a busy/loading indicator
|
Render a busy/loading indicator
|
||||||
*/
|
*/
|
||||||
(
|
<div
|
||||||
|
style={{
|
||||||
|
position: "fixed",
|
||||||
|
fontWeight: 500,
|
||||||
|
top: height / 2,
|
||||||
|
width,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "fixed",
|
display: "flex",
|
||||||
fontWeight: 500,
|
justifyContent: "center",
|
||||||
top: height / 2,
|
justifyItems: "center",
|
||||||
width,
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<Button minimal loading intent="primary" />
|
||||||
style={{
|
<span style={{ fontStyle: "italic" }}>Loading {displayName}</span>
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
justifyItems: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button minimal loading intent="primary" />
|
|
||||||
<span style={{ fontStyle: "italic" }}>Loading {displayName}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
</div>
|
||||||
;
|
);
|
||||||
|
|
||||||
export default Graph;
|
export default Graph;
|
||||||
|
|||||||
Reference in New Issue
Block a user