diff --git a/app/api/tiler.py b/app/api/tiler.py index 470930cd..83a85a0c 100644 --- a/app/api/tiler.py +++ b/app/api/tiler.py @@ -207,6 +207,8 @@ class Metadata(TaskNestedView): for b in info['statistics']: info['statistics'][b]['min'] = hrange[0] info['statistics'][b]['max'] = hrange[1] + info['statistics'][b]['percentiles'][0] = max(hrange[0], info['statistics'][b]['percentiles'][0]) + info['statistics'][b]['percentiles'][1] = min(hrange[1], info['statistics'][b]['percentiles'][1]) cmap_labels = { "viridis": "Viridis", diff --git a/app/static/app/js/components/Histogram.jsx b/app/static/app/js/components/Histogram.jsx index 9779b34e..2be1d7b4 100644 --- a/app/static/app/js/components/Histogram.jsx +++ b/app/static/app/js/components/Histogram.jsx @@ -10,13 +10,17 @@ export default class Histogram extends React.Component { colorMap: null, onUpdate: null, loading: false, + min: null, + max: null }; static propTypes = { statistics: PropTypes.object.isRequired, colorMap: PropTypes.array, width: PropTypes.number, onUpdate: PropTypes.func, - loading: PropTypes.bool + loading: PropTypes.bool, + min: PropTypes.number, + max: PropTypes.number } constructor(props){ @@ -53,11 +57,19 @@ export default class Histogram extends React.Component { this.rangeX = [minX, maxX]; this.rangeY = [minY, maxY]; + let min = minX; + let max = maxX; + + if (this.props.min !== null && this.props.max !== null){ + min = this.props.min; + max = this.props.max; + } + const st = { - min: minX.toFixed(3), - max: maxX.toFixed(3), - minInput: minX.toFixed(3), - maxInput: maxX.toFixed(3) + min: min, + max: max, + minInput: min.toFixed(3), + maxInput: max.toFixed(3) }; if (!this.state){ @@ -183,7 +195,7 @@ export default class Histogram extends React.Component { maxLine.setAttribute('x2', newX); if (prevX !== newX){ - self.setState({max: (self.rangeX[0] + ((self.rangeX[1] - self.rangeX[0]) / width) * newX).toFixed(3)}); + self.setState({max: (self.rangeX[0] + ((self.rangeX[1] - self.rangeX[0]) / width) * newX)}); } } }; @@ -201,7 +213,7 @@ export default class Histogram extends React.Component { minLine.setAttribute('x2', newX); if (prevX !== newX){ - self.setState({min: (self.rangeX[0] + ((self.rangeX[1] - self.rangeX[0]) / width) * newX).toFixed(3)}); + self.setState({min: (self.rangeX[0] + ((self.rangeX[1] - self.rangeX[0]) / width) * newX)}); } } }; @@ -237,8 +249,9 @@ export default class Histogram extends React.Component { } componentDidUpdate(prevProps, prevState){ - if (prevState.min !== this.state.min) this.state.minInput = this.state.min; - if (prevState.max !== this.state.max) this.state.maxInput = this.state.max; + if (prevState.min !== this.state.min || prevState.max !== this.state.max){ + this.setState({minInput: this.state.min.toFixed(3), maxInput: this.state.max.toFixed(3)}); + } if (prevState.min !== this.state.min || prevState.max !== this.state.max || @@ -277,28 +290,42 @@ export default class Histogram extends React.Component { handleChangeMax = (e) => { this.setState({maxInput: e.target.value}); - const val = parseFloat(e.target.value); + } - if (val >= this.state.min && val <= this.rangeX[1]){ - this.setState({max: val}); + handleMaxBlur = (e) => { + let val = parseFloat(e.target.value); + if (!isNaN(val)){ + val = Math.max(this.state.min, Math.min(this.rangeX[1], val)); + this.setState({max: val, maxInput: val.toFixed(3)}); } } + handleMaxKeyDown = (e) => { + if (e.key === 'Enter') this.handleMaxBlur(e); + } + handleChangeMin = (e) => { this.setState({minInput: e.target.value}); - const val = parseFloat(e.target.value); + } - if (val <= this.state.max && val >= this.rangeX[0]){ - this.setState({min: val}); + handleMinBlur = (e) => { + let val = parseFloat(e.target.value); + if (!isNaN(val)){ + val = Math.max(this.rangeX[0], Math.min(this.state.max, val)); + this.setState({min: val, minInput: val.toFixed(3)}); } + }; + + handleMinKeyDown = (e) => { + if (e.key === 'Enter') this.handleMinBlur(e); } render(){ return (
{ this.hgContainer = domNode; }}>
- - + +
); } } diff --git a/app/static/app/js/components/LayersControlLayer.jsx b/app/static/app/js/components/LayersControlLayer.jsx index 4996b01f..8de09ac6 100644 --- a/app/static/app/js/components/LayersControlLayer.jsx +++ b/app/static/app/js/components/LayersControlLayer.jsx @@ -65,7 +65,6 @@ export default class LayersControlLayer extends React.Component { exportLoading: false, error: "" }; - this.rescale = params.rescale || ""; } @@ -170,7 +169,14 @@ export default class LayersControlLayer extends React.Component { // Update rescale values const { statistics } = this.tmeta; if (statistics && statistics["1"]){ - this.rescale = `${statistics["1"]["min"]},${statistics["1"]["max"]}`; + let min = Infinity; + let max = -Infinity; + + for (let b in statistics){ + min = Math.min(statistics[b]["percentiles"][0]); + max = Math.max(statistics[b]["percentiles"][1]); + } + this.rescale = `${min},${max}`; } this.updateLayer(); @@ -270,6 +276,16 @@ export default class LayersControlLayer extends React.Component { cmapValues = (color_maps.find(c => c.key === colorMap) || {}).color_map; } + let hmin = null; + let hmax = null; + if (this.rescale){ + let parts = decodeURIComponent(this.rescale).split(","); + if (parts.length === 2 && parts[0] && parts[1]){ + hmin = parseFloat(parts[0]); + hmax = parseFloat(parts[1]); + } + } + return (
{!this.props.overlay ? :
} {meta.name} @@ -278,8 +294,10 @@ export default class LayersControlLayer extends React.Component {
diff --git a/app/static/app/js/components/Map.jsx b/app/static/app/js/components/Map.jsx index 2d6caacc..5bbd2f2f 100644 --- a/app/static/app/js/components/Map.jsx +++ b/app/static/app/js/components/Map.jsx @@ -169,7 +169,22 @@ class Map extends React.Component { const params = Utils.queryParams({search: tileUrl.slice(tileUrl.indexOf("?"))}); if (statistics["1"]){ // Add rescale - params["rescale"] = encodeURIComponent(`${statistics["1"]["min"]},${statistics["1"]["max"]}`); + let min = Infinity; + let max = -Infinity; + if (type === 'plant'){ + // percentile + for (let b in statistics){ + min = Math.min(statistics[b]["percentiles"][0]); + max = Math.max(statistics[b]["percentiles"][1]); + } + }else{ + // min/max + for (let b in statistics){ + min = Math.min(statistics[b]["min"]); + max = Math.max(statistics[b]["max"]); + } + } + params["rescale"] = encodeURIComponent(`${min},${max}`); }else{ console.warn("Cannot find min/max statistics for dataset, setting to -1,1"); params["rescale"] = encodeURIComponent("-1,1"); diff --git a/package.json b/package.json index 083eac4a..579a31c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "WebODM", - "version": "2.4.1", + "version": "2.4.2", "description": "User-friendly, extendable application and API for processing aerial imagery.", "main": "index.js", "scripts": {