delint components/graph

This commit is contained in:
bkmartinjr
2018-09-21 15:28:06 -04:00
committed by Colin Megill
parent 4543b002e3
commit 967ea21d8a
4 changed files with 138 additions and 130 deletions
+2 -1
View File
@@ -31,6 +31,7 @@ module.exports = {
"spaced-comment": ["error", "always", { exceptions: ["*"] }],
"no-param-reassign": "off",
"object-curly-newline": ["error", { consistent: true }],
"react/prop-types": [0]
"react/prop-types": [0],
"space-before-function-paren": "off"
}
};
@@ -38,9 +38,7 @@ export default function(regl) {
uniforms: {
distance: regl.prop("distance"),
view: regl.prop("view"),
projection: (context, props) => {
return mat4.perspective([], Math.PI / 2, 1, 0.01, 1000);
}
projection: () => mat4.perspective([], Math.PI / 2, 1, 0.01, 1000)
},
count: regl.prop("count"),
+133 -122
View File
@@ -1,37 +1,31 @@
// jshint esversion: 6
import React from "react";
import _ from "lodash";
import * as globals from "../../globals";
import styles from "./graph.css";
import { setupSVGandBrushElements } from "./setupSVGandBrush";
import SectionHeader from "../framework/sectionHeader";
import { connect } from "react-redux";
import actions from "../../actions";
import * as d3 from "d3";
import { connect } from "react-redux";
import mat4 from "gl-mat4";
import fit from "canvas-fit";
import _camera from "../../util/camera.js";
import _regl from "regl";
import _drawPoints from "./drawPointsRegl";
import { scaleLinear } from "../../util/scaleLinear";
import FaCrosshair from "react-icons/lib/fa/crosshairs";
import FaZoom from "react-icons/lib/fa/search-plus";
import FaSave from "react-icons/lib/fa/download";
import * as globals from "../../globals";
import setupSVGandBrushElements from "./setupSVGandBrush";
import actions from "../../actions";
import _camera from "../../util/camera";
import _drawPoints from "./drawPointsRegl";
import { scaleLinear } from "../../util/scaleLinear";
/* https://bl.ocks.org/mbostock/9078690 - quadtree for onClick / hover selections */
@connect(state => {
return {
world: state.controls.world,
crossfilter: state.controls.crossfilter,
responsive: state.responsive,
colorRGB: _.get(state.controls, "colorRGB", null),
opacityForDeselectedCells: state.controls.opacityForDeselectedCells,
selectionUpdate: _.get(state.controls, "crossfilter.updateTime", null)
};
})
@connect(state => ({
world: state.controls.world,
crossfilter: state.controls.crossfilter,
responsive: state.responsive,
colorRGB: _.get(state.controls, "colorRGB", null),
opacityForDeselectedCells: state.controls.opacityForDeselectedCells,
selectionUpdate: _.get(state.controls, "crossfilter.updateTime", null)
}))
class Graph extends React.Component {
constructor(props) {
super(props);
@@ -51,41 +45,6 @@ class Graph extends React.Component {
};
}
reglDraw(regl, drawPoints, sizeBuffer, colorBuffer, pointBuffer, camera) {
regl.clear({
depth: 1,
color: [1, 1, 1, 1]
});
drawPoints({
size: sizeBuffer,
distance: camera.distance,
color: colorBuffer,
position: pointBuffer,
count: this.count,
view: camera.view()
});
}
restartReglLoop() {
const reglRender = this.state.regl.frame(() => {
this.reglDraw(
this.state.regl,
this.state.drawPoints,
this.state.sizeBuffer,
this.state.colorBuffer,
this.state.pointBuffer,
this.state.camera
);
this.state.camera.tick();
});
this.reglRenderState = "rendering";
this.setState({
reglRender
});
}
componentDidMount() {
// setup canvas and camera
const camera = _camera(this.reglCanvas, { scale: true, rotate: false });
@@ -124,7 +83,7 @@ class Graph extends React.Component {
});
}
componentDidUpdate(prevProps, prevState) {
componentDidUpdate(prevProps) {
const {
world,
crossfilter,
@@ -132,19 +91,25 @@ class Graph extends React.Component {
colorRGB,
responsive
} = this.props;
const {
reglRender,
mode,
regl,
drawPoints,
camera,
pointBuffer,
colorBuffer,
sizeBuffer
} = this.state;
if (
this.state.reglRender &&
this.reglRenderState === "rendering" &&
this.state.mode !== "zoom"
) {
this.state.reglRender.cancel();
if (reglRender && this.reglRenderState === "rendering" && mode !== "zoom") {
reglRender.cancel();
this.reglRenderState = "paused";
}
if (this.state.regl && world) {
if (regl && world) {
/* update the regl state */
const obsLayout = world.obsLayout;
const { obsLayout } = world;
const cellCount = crossfilter.size();
// X/Y positions for each point - a cached value that only
@@ -152,23 +117,24 @@ class Graph extends React.Component {
//
if (
!this.renderCache.positions ||
selectionUpdate != prevProps.selectionUpdate
selectionUpdate !== prevProps.selectionUpdate
) {
if (!this.renderCache.positions)
if (!this.renderCache.positions) {
this.renderCache.positions = new Float32Array(2 * cellCount);
}
const glScaleX = scaleLinear([0, 1], [-1, 1]);
const glScaleY = scaleLinear([0, 1], [1, -1]);
for (
let i = 0, positions = this.renderCache.positions;
let i = 0, { positions } = this.renderCache;
i < cellCount;
i++
i += 1
) {
positions[2 * i] = glScaleX(obsLayout.X[i]);
positions[2 * i + 1] = glScaleY(obsLayout.Y[i]);
}
this.state.pointBuffer({
pointBuffer({
data: this.renderCache.positions,
dimension: 2
});
@@ -180,14 +146,15 @@ 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 || colorRGB != prevProps.colorRGB) {
if (!this.renderCache.colors || colorRGB !== prevProps.colorRGB) {
const rgb = colorRGB;
if (!this.renderCache.colors)
if (!this.renderCache.colors) {
this.renderCache.colors = new Float32Array(3 * rgb.length);
for (let i = 0, colors = this.renderCache.colors; i < rgb.length; i++) {
}
for (let i = 0, { colors } = this.renderCache; i < rgb.length; i += 1) {
colors.set(rgb[i], 3 * i);
}
this.state.colorBuffer({ data: this.renderCache.colors, dimension: 3 });
colorBuffer({ data: this.renderCache.colors, dimension: 3 });
}
// Sizes for each point - this is presumed to change each time the
@@ -195,21 +162,22 @@ class Graph extends React.Component {
// most property upates are due to changes driving a crossfilter
// selection set change.
//
if (!this.renderCache.sizes)
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 });
sizeBuffer({ data: this.renderCache.sizes, dimension: 1 });
this.count = cellCount;
this.state.regl._refresh();
regl._refresh();
this.reglDraw(
this.state.regl,
this.state.drawPoints,
this.state.sizeBuffer,
this.state.colorBuffer,
this.state.pointBuffer,
this.state.camera
regl,
drawPoints,
sizeBuffer,
colorBuffer,
pointBuffer,
camera
);
}
@@ -233,8 +201,58 @@ class Graph extends React.Component {
}
}
reglDraw(regl, drawPoints, sizeBuffer, colorBuffer, pointBuffer, camera) {
regl.clear({
depth: 1,
color: [1, 1, 1, 1]
});
drawPoints({
size: sizeBuffer,
distance: camera.distance,
color: colorBuffer,
position: pointBuffer,
count: this.count,
view: camera.view()
});
}
restartReglLoop() {
const {
regl,
drawPoints,
sizeBuffer,
colorBuffer,
pointBuffer,
camera
} = this.state;
const reglRender = regl.frame(() => {
this.reglDraw(
regl,
drawPoints,
sizeBuffer,
colorBuffer,
pointBuffer,
camera
);
camera.tick();
});
this.reglRenderState = "rendering";
this.setState({
reglRender
});
}
handleBrushSelectAction() {
/* This conditional handles procedural brush deselect. Brush emits an event on procedural deselect because it is move: null */
/*
This conditional handles procedural brush deselect. Brush emits
an event on procedural deselect because it is move: null
*/
const { camera } = this.state;
const { dispatch, responsive } = this.props;
if (d3.event.sourceEvent !== null) {
/*
No idea why d3 event scope works like this
@@ -252,18 +270,13 @@ class Graph extends React.Component {
*/
// compute inverse view matrix
const inverse = mat4.invert([], this.state.camera.view());
const inverse = mat4.invert([], camera.view());
// transform screen coordinates -> cell coordinates
const invert = pin => {
const x =
(2 * pin[0]) / (this.props.responsive.height - this.graphPaddingTop) -
1;
const x = (2 * pin[0]) / (responsive.height - this.graphPaddingTop) - 1;
const y =
2 *
(1 -
pin[1] / (this.props.responsive.height - this.graphPaddingTop)) -
1;
2 * (1 - pin[1] / (responsive.height - this.graphPaddingTop)) - 1;
const pout = [
x * inverse[14] + inverse[12],
y * inverse[14] + inverse[13]
@@ -276,7 +289,7 @@ class Graph extends React.Component {
southeast: invert([s[1][0], s[1][1]])
};
this.props.dispatch({
dispatch({
type: "graph brush selection change",
brushCoords
});
@@ -284,29 +297,38 @@ class Graph extends React.Component {
}
handleBrushDeselectAction() {
const { dispatch } = this.props;
const { svg, brush } = this.state;
if (d3.event && !d3.event.selection) {
this.props.dispatch({
dispatch({
type: "graph brush deselect"
});
}
if (!d3.event) {
/* this line clears the brush procedurally, ie., zoom button clicked, not a click away from brush on svg */
this.state.svg.select(".graph_brush").call(this.state.brush.move, null);
this.props.dispatch({
/*
this line clears the brush procedurally, ie., zoom button clicked,
not a click away from brush on svg
*/
svg.select(".graph_brush").call(brush.move, null);
dispatch({
type: "graph brush deselect"
});
}
}
handleOpacityRangeChange(e) {
this.props.dispatch({
const { dispatch } = this.props;
dispatch({
type: "change opacity deselected cells in 2d graph background",
data: e.target.value
});
}
render() {
const { dispatch, responsive } = this.props;
const { mode } = this.state;
return (
<div id="graphWrapper">
<div style={{ position: "fixed", right: 0, top: 0 }}>
@@ -319,8 +341,9 @@ class Graph extends React.Component {
}}
>
<button
type="button"
onClick={() => {
this.props.dispatch(actions.resetGraph());
dispatch(actions.resetGraph());
}}
style={{
fontSize: 14,
@@ -338,8 +361,9 @@ class Graph extends React.Component {
reset graph
</button>
<button
type="button"
onClick={() => {
this.props.dispatch(actions.regraph());
dispatch(actions.regraph());
}}
style={{
fontSize: 14,
@@ -359,15 +383,14 @@ class Graph extends React.Component {
<div>
<span>
<button
type="button"
onClick={() => {
this.setState({ mode: "brush" });
}}
style={{
cursor: "pointer",
border:
this.state.mode === "brush"
? "1px solid black"
: "1px solid white",
mode === "brush" ? "1px solid black" : "1px solid white",
backgroundColor: "white",
padding: 5,
marginRight: 10,
@@ -378,6 +401,7 @@ class Graph extends React.Component {
<FaCrosshair />{" "}
</button>
<button
type="button"
onClick={() => {
this.handleBrushDeselectAction();
this.restartReglLoop();
@@ -386,9 +410,7 @@ class Graph extends React.Component {
style={{
cursor: "pointer",
border:
this.state.mode === "zoom"
? "1px solid black"
: "1px solid white",
mode === "zoom" ? "1px solid black" : "1px solid white",
backgroundColor: "white",
padding: 5,
marginRight: 10,
@@ -402,6 +424,7 @@ class Graph extends React.Component {
</div>
<div>
<button
type="button"
style={{
fontSize: 14,
fontWeight: 400,
@@ -431,14 +454,14 @@ class Graph extends React.Component {
>
<div
style={{
display: this.state.mode === "brush" ? "inherit" : "none"
display: mode === "brush" ? "inherit" : "none"
}}
id="graphAttachPoint"
/>
<div style={{ padding: 0, margin: 0 }}>
<canvas
width={this.props.responsive.height - this.graphPaddingTop}
height={this.props.responsive.height - this.graphPaddingTop}
width={responsive.height - this.graphPaddingTop}
height={responsive.height - this.graphPaddingTop}
ref={canvas => {
this.reglCanvas = canvas;
}}
@@ -451,15 +474,3 @@ class Graph extends React.Component {
}
export default Graph;
// <span style={{ marginRight: 10, fontSize: 12 }}>
// deselected opacity
// </span>
// <input
// style={{ position: "relative", top: 6, marginRight: 20 }}
// type="range"
// onChange={this.handleOpacityRangeChange.bind(this)}
// min={0}
// max={1}
// step="0.01"
// />
@@ -1,8 +1,6 @@
// jshint esversion: 6
import styles from "./graph.css";
import _ from "lodash";
import * as globals from "../../globals";
import * as d3 from "d3";
import styles from "./graph.css";
/******************************************
*******************************************
@@ -10,7 +8,7 @@ import * as d3 from "d3";
*******************************************
******************************************/
export const setupSVGandBrushElements = (
export default (
handleBrushSelectAction,
handleBrushDeselectAction,
responsive,