diff --git a/src/components/continuous/histogramBrush.js b/src/components/continuous/histogramBrush.js index c33a2278..4ac59c34 100644 --- a/src/components/continuous/histogramBrush.js +++ b/src/components/continuous/histogramBrush.js @@ -36,6 +36,7 @@ class HistogramBrush extends React.Component { this.width = 300; this.height = 100; this.marginBottom = 20; + this.histogramCache = {}; this.state = { svg: null, @@ -47,6 +48,44 @@ class HistogramBrush extends React.Component { } componentDidMount() {} componentDidUpdate() {} + + calcHistogramCache(nextProps) { + // recalculate expensive stuff + const allValuesForContinuousFieldAsArray = _.map( + nextProps.currentCellSelection, + nextProps.metadataField + ); + + this.histogramCache.x = d3 + .scaleLinear() + .domain([nextProps.ranges.min, nextProps.ranges.max]) + .range([0, this.width]); + + this.histogramCache.y = d3 + .scaleLinear() + .range([this.height - this.marginBottom, 0]); + // .range([height - margin.bottom, margin.top]); + + this.histogramCache.bins = d3 + .histogram() + .domain(this.histogramCache.x.domain()) + .thresholds(40)(allValuesForContinuousFieldAsArray); + + this.histogramCache.numValues = allValuesForContinuousFieldAsArray.length; + } + + componentWillMount() { + this.calcHistogramCache(this.props); + } + componentWillReceiveProps(nextProps) { + if ( + this.props.metadataField !== nextProps.metadataField || + !this.histogramCache.x + ) { + this.calcHistogramCache(nextProps); + } + } + onBrush(selection, x) { return () => { if (d3.event.selection) { @@ -65,24 +104,10 @@ class HistogramBrush extends React.Component { }; } drawHistogram(svgRef) { - const allValuesForContinuousFieldAsArray = _.map( - this.props.currentCellSelection, - this.props.metadataField - ); - - var x = d3 - .scaleLinear() - .domain(d3.extent(allValuesForContinuousFieldAsArray, d => +d)) - .range([0, this.width]); - // .range([margin.left, width - margin.right]); - - var y = d3.scaleLinear().range([this.height - this.marginBottom, 0]); - // .range([height - margin.bottom, margin.top]); - - const bins = d3 - .histogram() - .domain(x.domain()) - .thresholds(40)(allValuesForContinuousFieldAsArray); + const x = this.histogramCache.x; + const y = this.histogramCache.y; + const bins = this.histogramCache.bins; + const numValues = this.histogramCache.numValues; d3 .select(svgRef) @@ -96,13 +121,13 @@ class HistogramBrush extends React.Component { return x(d.x0) + 1; }) .attr("y", function(d) { - return y(d.length / allValuesForContinuousFieldAsArray.length); + return y(d.length / numValues); }) .attr("width", function(d) { return Math.abs(x(d.x1) - x(d.x0) - 1); }) .attr("height", function(d) { - return y(0) - y(d.length / allValuesForContinuousFieldAsArray.length); + return y(0) - y(d.length / numValues); }); if (!this.state.brush && !this.state.axis) { diff --git a/src/components/graph/graph.js b/src/components/graph/graph.js index 37f8ce5e..122ca2b6 100644 --- a/src/components/graph/graph.js +++ b/src/components/graph/graph.js @@ -113,35 +113,43 @@ class Graph extends React.Component { if (this.state.regl && nextProps.vertices) { const vertices = nextProps.currentCellSelection; const vertexCount = vertices.length; - const positions = new Float32Array(2 * vertexCount); const colors = new Float32Array(3 * vertexCount); const sizes = new Float32Array(vertexCount); - // 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]); + // Cache a scaled graph + if (!this.scaledGraphVec || this.props.graphVec !== nextProps.graphVec) { + const positions = new Float32Array(2 * vertexCount); + + // 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]); + + const graphVec = nextProps.graphVec; + for (var i = 0; i < vertexCount; i++) { + const cell = vertices[i]; + const cellIdx = cell.__cellIndex__; + + const x = glScaleX(graphVec[2 * cellIdx]); + const y = glScaleY(graphVec[2 * cellIdx + 1]); + positions[2 * i] = x; + positions[2 * i + 1] = y; + } + this.scaledGraphVec = positions; + } /* - Construct Vectors + Construct Size & Color Vectors */ - const graphVec = nextProps.graphVec; for (var i = 0; i < vertexCount; i++) { const cell = vertices[i]; - const cellIdx = cell.__cellIndex__; - const x = glScaleX(graphVec[2 * cellIdx]); - const y = glScaleY(graphVec[2 * cellIdx + 1]); - positions[2 * i] = x; - positions[2 * i + 1] = y; - colors.set(cell.__colorRGB__, 3 * i); - sizes[i] = cell.__selected__ ? 4 : 0.2; /* make this a function of the number of total cells, including regraph */ } - this.state.pointBuffer({ data: positions, dimension: 2 }); + this.state.pointBuffer({ data: this.scaledGraphVec, dimension: 2 }); this.state.colorBuffer({ data: colors, dimension: 3 }); this.state.sizeBuffer({ data: sizes, dimension: 1 }); this.count = vertexCount; diff --git a/src/middleware/updateCellSelectionMiddleware.js b/src/middleware/updateCellSelectionMiddleware.js index 1e29ea38..9e8dea24 100644 --- a/src/middleware/updateCellSelectionMiddleware.js +++ b/src/middleware/updateCellSelectionMiddleware.js @@ -49,7 +49,10 @@ const updateCellSelectionMiddleware = store => { - metadata has cellname and index, and that's all we ever need to reference cell info */ let newSelection = s.controls.currentCellSelection.slice(0); - _.forEach(newSelection, cell => (cell.__selected__ = true)); + // _.forEach(newSelection, cell => (cell.__selected__ = true)); + for (let i = 0; i < newSelection.length; i++) { + newSelection[i].__selected__ = true; + } /* in plain language...