kopia lustrzana https://github.com/OpenDroneMap/WebODM
Porównaj commity
5 Commity
e8f8f2f130
...
10a44851ac
Autor | SHA1 | Data |
---|---|---|
Piero Toffanin | 10a44851ac | |
Piero Toffanin | c2c65a2cc2 | |
Piero Toffanin | b1fdcbb242 | |
Piero Toffanin | 02b4132daa | |
Piero Toffanin | ed6a43699f |
|
@ -207,6 +207,8 @@ class Metadata(TaskNestedView):
|
||||||
for b in info['statistics']:
|
for b in info['statistics']:
|
||||||
info['statistics'][b]['min'] = hrange[0]
|
info['statistics'][b]['min'] = hrange[0]
|
||||||
info['statistics'][b]['max'] = hrange[1]
|
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 = {
|
cmap_labels = {
|
||||||
"viridis": "Viridis",
|
"viridis": "Viridis",
|
||||||
|
|
|
@ -10,13 +10,17 @@ export default class Histogram extends React.Component {
|
||||||
colorMap: null,
|
colorMap: null,
|
||||||
onUpdate: null,
|
onUpdate: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
min: null,
|
||||||
|
max: null
|
||||||
};
|
};
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
statistics: PropTypes.object.isRequired,
|
statistics: PropTypes.object.isRequired,
|
||||||
colorMap: PropTypes.array,
|
colorMap: PropTypes.array,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
onUpdate: PropTypes.func,
|
onUpdate: PropTypes.func,
|
||||||
loading: PropTypes.bool
|
loading: PropTypes.bool,
|
||||||
|
min: PropTypes.number,
|
||||||
|
max: PropTypes.number
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props){
|
constructor(props){
|
||||||
|
@ -53,11 +57,19 @@ export default class Histogram extends React.Component {
|
||||||
this.rangeX = [minX, maxX];
|
this.rangeX = [minX, maxX];
|
||||||
this.rangeY = [minY, maxY];
|
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 = {
|
const st = {
|
||||||
min: minX.toFixed(3),
|
min: min,
|
||||||
max: maxX.toFixed(3),
|
max: max,
|
||||||
minInput: minX.toFixed(3),
|
minInput: min.toFixed(3),
|
||||||
maxInput: maxX.toFixed(3)
|
maxInput: max.toFixed(3)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!this.state){
|
if (!this.state){
|
||||||
|
@ -183,7 +195,7 @@ export default class Histogram extends React.Component {
|
||||||
maxLine.setAttribute('x2', newX);
|
maxLine.setAttribute('x2', newX);
|
||||||
|
|
||||||
if (prevX !== 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);
|
minLine.setAttribute('x2', newX);
|
||||||
|
|
||||||
if (prevX !== 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){
|
componentDidUpdate(prevProps, prevState){
|
||||||
if (prevState.min !== this.state.min) this.state.minInput = this.state.min;
|
if (prevState.min !== this.state.min || prevState.max !== this.state.max){
|
||||||
if (prevState.max !== this.state.max) this.state.maxInput = this.state.max;
|
this.setState({minInput: this.state.min.toFixed(3), maxInput: this.state.max.toFixed(3)});
|
||||||
|
}
|
||||||
|
|
||||||
if (prevState.min !== this.state.min ||
|
if (prevState.min !== this.state.min ||
|
||||||
prevState.max !== this.state.max ||
|
prevState.max !== this.state.max ||
|
||||||
|
@ -277,28 +290,42 @@ export default class Histogram extends React.Component {
|
||||||
|
|
||||||
handleChangeMax = (e) => {
|
handleChangeMax = (e) => {
|
||||||
this.setState({maxInput: e.target.value});
|
this.setState({maxInput: e.target.value});
|
||||||
const val = parseFloat(e.target.value);
|
}
|
||||||
|
|
||||||
if (val >= this.state.min && val <= this.rangeX[1]){
|
handleMaxBlur = (e) => {
|
||||||
this.setState({max: val});
|
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) => {
|
handleChangeMin = (e) => {
|
||||||
this.setState({minInput: e.target.value});
|
this.setState({minInput: e.target.value});
|
||||||
const val = parseFloat(e.target.value);
|
}
|
||||||
|
|
||||||
if (val <= this.state.max && val >= this.rangeX[0]){
|
handleMinBlur = (e) => {
|
||||||
this.setState({min: val});
|
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(){
|
render(){
|
||||||
return (<div className={"histogram " + (this.props.loading ? "disabled" : "")}>
|
return (<div className={"histogram " + (this.props.loading ? "disabled" : "")}>
|
||||||
<div ref={(domNode) => { this.hgContainer = domNode; }}>
|
<div ref={(domNode) => { this.hgContainer = domNode; }}>
|
||||||
</div>
|
</div>
|
||||||
<label>{_("Min:")}</label> <input onChange={this.handleChangeMin} type="number" className="form-control min-max" size={5} value={this.state.minInput} />
|
<label>{_("Min:")}</label> <input onKeyDown={this.handleMinKeyDown} onBlur={this.handleMinBlur} onChange={this.handleChangeMin} type="number" className="form-control min-max" size={5} value={this.state.minInput} />
|
||||||
<label>{_("Max:")}</label> <input onChange={this.handleChangeMax} type="number" className="form-control min-max" size={5} value={this.state.maxInput} />
|
<label>{_("Max:")}</label> <input onKeyDown={this.handleMaxKeyDown} onBlur={this.handleMaxBlur} onChange={this.handleChangeMax} type="number" className="form-control min-max" size={5} value={this.state.maxInput} />
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,6 @@ export default class LayersControlLayer extends React.Component {
|
||||||
exportLoading: false,
|
exportLoading: false,
|
||||||
error: ""
|
error: ""
|
||||||
};
|
};
|
||||||
|
|
||||||
this.rescale = params.rescale || "";
|
this.rescale = params.rescale || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +169,14 @@ export default class LayersControlLayer extends React.Component {
|
||||||
// Update rescale values
|
// Update rescale values
|
||||||
const { statistics } = this.tmeta;
|
const { statistics } = this.tmeta;
|
||||||
if (statistics && statistics["1"]){
|
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();
|
this.updateLayer();
|
||||||
|
@ -270,6 +276,16 @@ export default class LayersControlLayer extends React.Component {
|
||||||
cmapValues = (color_maps.find(c => c.key === colorMap) || {}).color_map;
|
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 (<div className="layers-control-layer">
|
return (<div className="layers-control-layer">
|
||||||
{!this.props.overlay ? <ExpandButton bind={[this, 'expanded']} /> : <div className="overlayIcon"><i className={meta.icon || "fa fa-vector-square fa-fw"}></i></div>}<Checkbox bind={[this, 'visible']}/>
|
{!this.props.overlay ? <ExpandButton bind={[this, 'expanded']} /> : <div className="overlayIcon"><i className={meta.icon || "fa fa-vector-square fa-fw"}></i></div>}<Checkbox bind={[this, 'visible']}/>
|
||||||
<a title={meta.name} className="layer-label" href="javascript:void(0);" onClick={this.handleLayerClick}>{meta.name}</a>
|
<a title={meta.name} className="layer-label" href="javascript:void(0);" onClick={this.handleLayerClick}>{meta.name}</a>
|
||||||
|
@ -278,8 +294,10 @@ export default class LayersControlLayer extends React.Component {
|
||||||
<div className="layer-expanded">
|
<div className="layer-expanded">
|
||||||
<Histogram width={274}
|
<Histogram width={274}
|
||||||
loading={histogramLoading}
|
loading={histogramLoading}
|
||||||
statistics={tmeta.statistics}
|
statistics={tmeta.statistics}
|
||||||
colorMap={cmapValues}
|
colorMap={cmapValues}
|
||||||
|
min={hmin}
|
||||||
|
max={hmax}
|
||||||
onUpdate={this.handleHistogramUpdate} />
|
onUpdate={this.handleHistogramUpdate} />
|
||||||
|
|
||||||
<ErrorMessage bind={[this, "error"]} />
|
<ErrorMessage bind={[this, "error"]} />
|
||||||
|
|
|
@ -169,7 +169,22 @@ class Map extends React.Component {
|
||||||
const params = Utils.queryParams({search: tileUrl.slice(tileUrl.indexOf("?"))});
|
const params = Utils.queryParams({search: tileUrl.slice(tileUrl.indexOf("?"))});
|
||||||
if (statistics["1"]){
|
if (statistics["1"]){
|
||||||
// Add rescale
|
// 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{
|
}else{
|
||||||
console.warn("Cannot find min/max statistics for dataset, setting to -1,1");
|
console.warn("Cannot find min/max statistics for dataset, setting to -1,1");
|
||||||
params["rescale"] = encodeURIComponent("-1,1");
|
params["rescale"] = encodeURIComponent("-1,1");
|
||||||
|
@ -633,6 +648,7 @@ _('Example:'),
|
||||||
ref={(ref) => { this.shareButton = ref; }}
|
ref={(ref) => { this.shareButton = ref; }}
|
||||||
task={this.state.singleTask}
|
task={this.state.singleTask}
|
||||||
linksTarget="map"
|
linksTarget="map"
|
||||||
|
queryParams={{t: this.props.mapType}}
|
||||||
/>
|
/>
|
||||||
: ""}
|
: ""}
|
||||||
<SwitchModeButton
|
<SwitchModeButton
|
||||||
|
|
|
@ -12,7 +12,8 @@ class ShareButton extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
task: PropTypes.object.isRequired,
|
task: PropTypes.object.isRequired,
|
||||||
linksTarget: PropTypes.oneOf(['map', '3d']).isRequired,
|
linksTarget: PropTypes.oneOf(['map', '3d']).isRequired,
|
||||||
popupPlacement: PropTypes.string
|
popupPlacement: PropTypes.string,
|
||||||
|
queryParams: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props){
|
constructor(props){
|
||||||
|
@ -45,6 +46,7 @@ class ShareButton extends React.Component {
|
||||||
taskChanged={this.handleTaskChanged}
|
taskChanged={this.handleTaskChanged}
|
||||||
placement={this.props.popupPlacement}
|
placement={this.props.popupPlacement}
|
||||||
linksTarget={this.props.linksTarget}
|
linksTarget={this.props.linksTarget}
|
||||||
|
queryParams={this.props.queryParams}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -15,7 +15,8 @@ class SharePopup extends React.Component{
|
||||||
task: PropTypes.object.isRequired,
|
task: PropTypes.object.isRequired,
|
||||||
linksTarget: PropTypes.oneOf(['map', '3d']).isRequired,
|
linksTarget: PropTypes.oneOf(['map', '3d']).isRequired,
|
||||||
placement: PropTypes.string,
|
placement: PropTypes.string,
|
||||||
taskChanged: PropTypes.func
|
taskChanged: PropTypes.func,
|
||||||
|
queryParams: PropTypes.object
|
||||||
};
|
};
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
|
@ -38,7 +39,11 @@ class SharePopup extends React.Component{
|
||||||
}
|
}
|
||||||
|
|
||||||
getRelShareLink = () => {
|
getRelShareLink = () => {
|
||||||
return `/public/task/${this.props.task.id}/${this.props.linksTarget}/`;
|
let url = `/public/task/${this.props.task.id}/${this.props.linksTarget}/`;
|
||||||
|
if (this.props.queryParams){
|
||||||
|
url += Utils.toSearchQuery(this.props.queryParams);
|
||||||
|
}
|
||||||
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(){
|
componentDidMount(){
|
||||||
|
@ -86,8 +91,8 @@ class SharePopup extends React.Component{
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
const shareLink = Utils.absoluteUrl(this.state.relShareLink);
|
const shareLink = Utils.absoluteUrl(this.getRelShareLink());
|
||||||
const iframeUrl = Utils.absoluteUrl(`public/task/${this.state.task.id}/iframe/${this.props.linksTarget}/`);
|
const iframeUrl = Utils.absoluteUrl(`public/task/${this.state.task.id}/iframe/${this.props.linksTarget}/${Utils.toSearchQuery(this.props.queryParams)}`);
|
||||||
const iframeCode = `<iframe scrolling="no" title="WebODM" width="61.8033%" height="360" frameBorder="0" src="${iframeUrl}"></iframe>`;
|
const iframeCode = `<iframe scrolling="no" title="WebODM" width="61.8033%" height="360" frameBorder="0" src="${iframeUrl}"></iframe>`;
|
||||||
|
|
||||||
return (<div onMouseDown={e => { e.stopPropagation(); }} className={"sharePopup " + this.props.placement}>
|
return (<div onMouseDown={e => { e.stopPropagation(); }} className={"sharePopup " + this.props.placement}>
|
||||||
|
|
|
@ -29,7 +29,8 @@ def handle_map(request, template, task_pk=None, hide_title=False):
|
||||||
'map-items': json.dumps([task.get_map_items()]),
|
'map-items': json.dumps([task.get_map_items()]),
|
||||||
'title': task.name if not hide_title else '',
|
'title': task.name if not hide_title else '',
|
||||||
'public': 'true',
|
'public': 'true',
|
||||||
'share-buttons': 'false' if settings.DESKTOP_MODE else 'true'
|
'share-buttons': 'false' if settings.DESKTOP_MODE else 'true',
|
||||||
|
'selected-map-type': request.GET.get('t', 'auto'),
|
||||||
}.items()
|
}.items()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "WebODM",
|
"name": "WebODM",
|
||||||
"version": "2.4.1",
|
"version": "2.4.2",
|
||||||
"description": "User-friendly, extendable application and API for processing aerial imagery.",
|
"description": "User-friendly, extendable application and API for processing aerial imagery.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
Ładowanie…
Reference in New Issue