import React from 'react'; import PropTypes from 'prop-types'; import './MeasurePopup.scss'; import Utils from 'webodm/classes/Utils'; import Workers from 'webodm/classes/Workers'; import { _, interpolate } from 'webodm/classes/gettext'; import $ from 'jquery'; import L from 'leaflet'; export default class MeasurePopup extends React.Component { static defaultProps = { map: {}, model: {}, resultFeature: {} }; static propTypes = { map: PropTypes.object.isRequired, model: PropTypes.object.isRequired, resultFeature: PropTypes.object.isRequired } constructor(props){ super(props); let featureType = "Point"; if (props.model.area !== 0) featureType = "Polygon"; else if (props.model.length > 0) featureType = "LineString"; this.state = { featureType, volume: null, // to be calculated, baseMethod: localStorage.getItem("measure_base_method") || "triangulate", task: null, error: "" }; this.exportMeasurement = this.exportMeasurement.bind(this); this.getProperties = this.getProperties.bind(this); this.getGeoJSON = this.getGeoJSON.bind(this); } componentDidMount(){ if (this.state.featureType == "Polygon") this.calculateVolume(); this.props.resultFeature._measurePopup = this; } componentWillUnmount(){ this.props.resultFeature._measurePopup = null; } getProperties(){ const result = { Length: this.props.model.length, Area: this.props.model.area }; if (this.state.volume !== null && this.state.volume !== false){ result.Volume = this.state.volume; result.BaseSurface = this.state.baseMethod; } return result; } getGeoJSON(){ const geoJSON = this.props.resultFeature.toGeoJSON(); geoJSON.properties = this.getProperties(); return geoJSON; } exportMeasurement(){ const geoJSON = { type: "FeatureCollection", features: [this.getGeoJSON()] }; Utils.saveAs(JSON.stringify(geoJSON, null, 4), "measurement.geojson") } handleBaseMethodChange = (e) => { this.setState({baseMethod: e.target.value}); localStorage.setItem("measure_base_method", e.target.value); setTimeout(() => { this.recalculateVolume(); }, 0); } calculateVolume(){ const { lastCoord } = this.props.model; let layers = this.getLayersAtCoords(L.latLng( lastCoord.dd.y, lastCoord.dd.x )); // Did we select a layer? if (layers.length > 0){ const layer = layers[layers.length - 1]; const meta = layer[Symbol.for("meta")]; if (meta){ this.setState({task: meta.task}); setTimeout(() => { this.recalculateVolume(); }, 0); }else{ console.warn("Cannot find [meta] symbol for layer: ", layer); this.setState({volume: false}); } }else{ this.setState({volume: false}); } } recalculateVolume = () => { const { task, baseMethod } = this.state; if (!task) return; this.setState({volume: null, error: ""}); $.ajax({ type: 'POST', url: `/api/plugins/measure/task/${task.id}/volume`, data: JSON.stringify({ area: this.props.resultFeature.toGeoJSON(), method: baseMethod }), contentType: "application/json" }).done(result => { if (result.celery_task_id){ Workers.waitForCompletion(result.celery_task_id, error => { if (error) this.setState({error}); else{ Workers.getOutput(result.celery_task_id, (error, volume) => { if (error) this.setState({error}); else this.setState({volume: parseFloat(volume)}); }, `/api/plugins/measure/task/${task.id}/volume/get/`); } }, `/api/plugins/measure/task/${task.id}/volume/check/`); }else if (result.error){ this.setState({error: result.error}); }else{ this.setState({error: interpolate(_("Invalid response: %(error)s"), { error: result})}); } }).fail(error => { this.setState({error}); }); } // @return the layers in the map // at a specific lat/lon getLayersAtCoords(latlng){ const targetBounds = L.latLngBounds(latlng, latlng); const intersects = []; for (let l in this.props.map._layers){ const layer = this.props.map._layers[l]; if (layer.options && layer.options.bounds){ if (targetBounds.intersects(layer.options.bounds)){ intersects.push(layer); } } } return intersects; } render(){ const { volume, error, featureType } = this.state; const baseMethods = [ {label: _("Triangulate"), method: 'triangulate'}, {label: _("Plane"), method: 'plane'}, {label: _("Average"), method: 'average'}, {label: _("Highest"), method: 'highest'}, {label: _("Lowest"), method: 'lowest'}]; return (
{_("Area:")} {this.props.model.areaDisplay}
} {featureType == "Polygon" &&{_("Perimeter:")} {this.props.model.lengthDisplay}
} {featureType == "Polygon" && volume === null && !error &&{_("Volume:")} {_("computing…")}
} {typeof volume === "number" ? [{_("Volume:")} {volume.toFixed("2")} {_("Cubic Meters")} ({(volume * 35.3147).toFixed(2)} {_("Cubic Feet")})
,{_("Base surface:")}
] : ""} {error &&{_("Volume:")} 200 ? 'long' : '')}>{error}
} {_("Export to GeoJSON")}