Add frontend

This commit is contained in:
Emanuele Bezzi
2021-12-01 16:49:13 -05:00
parent 54d4de431c
commit db0f50d011
2 changed files with 86 additions and 24 deletions
@@ -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,
});
}
+48 -24
View File
@@ -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;