From 8f16c17e3406623c576e926c57442b56b55b026e Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Tue, 26 Nov 2019 10:56:35 -0500 Subject: [PATCH] Rescale update working --- app/api/tiler.py | 38 +++++++++--- app/static/app/js/components/Histogram.jsx | 14 +++-- .../app/js/components/LayersControlLayer.jsx | 62 ++++++++++++++++--- 3 files changed, 93 insertions(+), 21 deletions(-) diff --git a/app/api/tiler.py b/app/api/tiler.py index 8c076dbd..f1623df2 100644 --- a/app/api/tiler.py +++ b/app/api/tiler.py @@ -59,13 +59,18 @@ def rescale_tile(tile, mask, rescale = None): if len(rescale_arr) != tile.shape[0]: rescale_arr = ((rescale_arr[0]),) * tile.shape[0] for bdx in range(tile.shape[0]): - tile[bdx] = np.where( - mask, - linear_rescale( + if mask is not None: + tile[bdx] = np.where( + mask, + linear_rescale( + tile[bdx], in_range=rescale_arr[bdx], out_range=[0, 255] + ), + 0, + ) + else: + tile[bdx] = linear_rescale( tile[bdx], in_range=rescale_arr[bdx], out_range=[0, 255] - ), - 0, - ) + ) tile = tile.astype(np.uint8) return tile, mask @@ -120,14 +125,20 @@ class Metadata(TaskNestedView): """ task = self.get_and_check_task(request, pk) - expr = lookup_formula(self.request.query_params.get('formula'), self.request.query_params.get('bands')) + formula = self.request.query_params.get('formula') + bands = self.request.query_params.get('bands') color_map = self.request.query_params.get('color_map') + if formula == '': formula = None + if bands == '': bands = None + if color_map == '': color_map = None + + expr = lookup_formula(formula, bands) + pmin, pmax = 2.0, 98.0 raster_path = get_raster_path(task, tile_type) info = main.metadata(raster_path, pmin=pmin, pmax=pmax, histogram_bins=255, expr=expr) - if tile_type == 'plant': info['algorithms'] = get_algorithm_list(), info['filters'] = get_camera_filters_list() @@ -195,12 +206,19 @@ class Tiles(TaskNestedView): indexes = None nodata = None - expr = lookup_formula(self.request.query_params.get('formula'), self.request.query_params.get('bands')) + formula = self.request.query_params.get('formula') + bands = self.request.query_params.get('bands') rescale = self.request.query_params.get('rescale') color_map = self.request.query_params.get('color_map') hillshade = self.request.query_params.get('hillshade') - # TODO: server-side expressions + if formula == '': formula = None + if bands == '': bands = None + if rescale == '': rescale = None + if color_map == '': color_map = None + if hillshade == '': hillshade = None + + expr = lookup_formula(formula, bands) if tile_type in ['dsm', 'dtm'] and rescale is None: raise exceptions.ValidationError("Cannot get tiles without rescale parameter. Add ?rescale=min,max to the URL.") diff --git a/app/static/app/js/components/Histogram.jsx b/app/static/app/js/components/Histogram.jsx index 4c52d2ca..80f4e824 100644 --- a/app/static/app/js/components/Histogram.jsx +++ b/app/static/app/js/components/Histogram.jsx @@ -6,12 +6,14 @@ import d3 from 'd3'; export default class Histogram extends React.Component { static defaultProps = { width: 280, - colorMap: null + colorMap: null, + onUpdate: null }; static propTypes = { statistics: PropTypes.object.isRequired, colorMap: PropTypes.array, - width: PropTypes.number + width: PropTypes.number, + onUpdate: PropTypes.func } constructor(props){ @@ -132,7 +134,7 @@ export default class Histogram extends React.Component { .attr('x2', minXStart) .attr('y2', height) .attr('class', 'theme-stroke-primary slider-line min') - .on("mousedown", function(){ self.minDown = true; })[0][0]; + .on("mousedown", function(){ self.maxDown = false; self.minDown = true; })[0][0]; const maxXStart = ((this.state.max - this.rangeX[0]) / (this.rangeX[1] - this.rangeX[0])) * width; @@ -143,7 +145,7 @@ export default class Histogram extends React.Component { .attr('x2', maxXStart) .attr('y2', height) .attr('class', 'theme-stroke-primary slider-line max') - .on("mousedown", function(){ self.maxDown = true; })[0][0]; + .on("mousedown", function(){ self.minDown = false; self.maxDown = true; })[0][0]; const handleLeave = () => { this.maxDown = this.minDown = false; @@ -224,10 +226,14 @@ export default class Histogram extends React.Component { prevState.max !== this.state.max){ if (!this.maxDown && !this.minDown) this.redraw(); this.updateColorMap(); + + if (this.props.onUpdate !== undefined) this.props.onUpdate({min: this.state.min, max: this.state.max}); } } updateColorMap = () => { + if (!this.colorMapElem) return; + const { min, max } = this.state; const minPerc = Math.abs(min - this.rangeX[0]) / (this.rangeX[1] - this.rangeX[0]) * 100.0; diff --git a/app/static/app/js/components/LayersControlLayer.jsx b/app/static/app/js/components/LayersControlLayer.jsx index af26e4d6..25c19478 100644 --- a/app/static/app/js/components/LayersControlLayer.jsx +++ b/app/static/app/js/components/LayersControlLayer.jsx @@ -20,7 +20,7 @@ export default class LayersControlLayer extends React.Component { this.map = props.layer._map; - const url = this.props.layer._url; + const url = this.getLayerUrl(); const params = Utils.queryParams({search: url.slice(url.indexOf("?"))}); this.colorMaps = [ @@ -37,8 +37,17 @@ export default class LayersControlLayer extends React.Component { this.state = { visible: true, expanded: props.expanded, - color: params.color_map + color_map: params.color_map || "", + formula: params.formula || "", + bands: params.bands || "", + hillshade: params.hillshade || "" }; + + this.rescale = ""; + } + + getLayerUrl = () => { + return this.props.layer._url; } componentDidUpdate(prevProps, prevState){ @@ -59,12 +68,50 @@ export default class LayersControlLayer extends React.Component { } handleSelectColor = e => { - this.setState({color: e.target.value}); + this.setState({color_map: e.target.value}); + } + + updateLayer = () => { + if (this.updateTimer){ + clearTimeout(this.updateTimer); + this.updateTimer = null; + } + + this.updateTimer = setTimeout(() => { + const url = this.getLayerUrl(); + const { color_map, + formula, + bands, + hillshade } = this.state; + + const newUrl = (url.indexOf("?") !== -1 ? url.slice(0, url.indexOf("?")) : url) + Utils.toSearchQuery({ + color_map, + formula, + bands, + hillshade, + rescale: encodeURIComponent(this.rescale) + }); + + const { layer } = this.props; + + layer.setUrl(newUrl, true); + + // Hack to get leaflet to actually redraw tiles :/ + layer._removeAllTiles(); + setTimeout(() => { + layer.redraw(); + }, 1); + }, 200); + } + + handleHistogramUpdate = e => { + this.rescale = `${e.min},${e.max}`; + this.updateLayer(); } render(){ const { layer } = this.props; - const { color } = this.state; + const { color_map } = this.state; const tmeta = layer[Symbol.for("tile-meta")]; const meta = layer[Symbol.for("meta")]; @@ -77,13 +124,14 @@ export default class LayersControlLayer extends React.Component {
+ colorMap={tmeta.color_map} + onUpdate={this.handleHistogramUpdate} /> - {this.state.color ? + {this.state.color_map ?
- {this.colorMaps.map(c => )}