import React from 'react'; import PropTypes from 'prop-types'; import Storage from 'webodm/classes/Storage'; import L from 'leaflet'; import './ContoursPanel.scss'; import ErrorMessage from 'webodm/components/ErrorMessage'; import Workers from 'webodm/classes/Workers'; import { _ } from 'webodm/classes/gettext'; export default class ContoursPanel extends React.Component { static defaultProps = { }; static propTypes = { onClose: PropTypes.func.isRequired, tasks: PropTypes.object.isRequired, isShowed: PropTypes.bool.isRequired, map: PropTypes.object.isRequired } constructor(props){ super(props); this.state = { error: "", permanentError: "", interval: Storage.getItem("last_contours_interval") || "1", customInterval: Storage.getItem("last_contours_custom_interval") || "1", simplify: Storage.getItem("last_contours_simplify") || "0.2", customSimplify: Storage.getItem("last_contours_custom_simplify") || "0.2", layer: "", epsg: Storage.getItem("last_contours_epsg") || "4326", customEpsg: Storage.getItem("last_contours_custom_epsg") || "4326", layers: [], loading: true, task: props.tasks[0] || null, previewLoading: false, exportLoading: false, previewLayer: null, }; } componentDidUpdate(){ if (this.props.isShowed && this.state.loading){ const {id, project} = this.state.task; this.loadingReq = $.getJSON(`/api/projects/${project}/tasks/${id}/`) .done(res => { const { available_assets } = res; let layers = []; if (available_assets.indexOf("dsm.tif") !== -1) layers.push("DSM"); if (available_assets.indexOf("dtm.tif") !== -1) layers.push("DTM"); if (layers.length > 0){ this.setState({layers, layer: layers[0]}); }else{ this.setState({permanentError: _("No DSM or DTM is available. To export contours, make sure to process a task with either the --dsm or --dtm option checked.")}); } }) .fail(() => { this.setState({permanentError: _("Cannot retrieve information for task. Are you are connected to the internet?")}) }) .always(() => { this.setState({loading: false}); this.loadingReq = null; }); } } componentWillUnmount(){ if (this.loadingReq){ this.loadingReq.abort(); this.loadingReq = null; } if (this.generateReq){ this.generateReq.abort(); this.generateReq = null; } } handleSelectInterval = e => { this.setState({interval: e.target.value}); } handleSelectSimplify = e => { this.setState({simplify: e.target.value}); } handleChangeCustomSimplify = e => { this.setState({customSimplify: e.target.value}); } handleSelectLayer = e => { this.setState({layer: e.target.value}); } handleChangeCustomInterval = e => { this.setState({customInterval: e.target.value}); } handleSelectEpsg = e => { this.setState({epsg: e.target.value}); } handleChangeCustomEpsg = e => { this.setState({customEpsg: e.target.value}); } getFormValues = () => { const { interval, customInterval, epsg, customEpsg, simplify, customSimplify, layer } = this.state; return { interval: interval !== "custom" ? interval : customInterval, epsg: epsg !== "custom" ? epsg : customEpsg, simplify: simplify !== "custom" ? simplify : customSimplify, layer }; } addGeoJSONFromURL = (url, cb) => { const { map } = this.props; $.getJSON(url) .done((geojson) => { try{ this.handleRemovePreview(); this.setState({previewLayer: L.geoJSON(geojson, { onEachFeature: (feature, layer) => { if (feature.properties && feature.properties.level !== undefined) { layer.bindPopup(`${_("Elevation:")} ${feature.properties.level} ${_("meters")}`); } }, style: feature => { // TODO: different colors for different elevations? return {color: "yellow"}; } })}); this.state.previewLayer.addTo(map); cb(); }catch(e){ cb(e.message); } }) .fail(cb); } handleRemovePreview = () => { const { map } = this.props; if (this.state.previewLayer){ map.removeLayer(this.state.previewLayer); this.setState({previewLayer: null}); } } generateContours = (data, loadingProp, isPreview) => { this.setState({[loadingProp]: true, error: ""}); const taskId = this.state.task.id; // Save settings for next time Storage.setItem("last_contours_interval", this.state.interval); Storage.setItem("last_contours_custom_interval", this.state.customInterval); Storage.setItem("last_contours_simplify", this.state.simplify); Storage.setItem("last_contours_custom_simplify", this.state.customSimplify); Storage.setItem("last_contours_epsg", this.state.epsg); Storage.setItem("last_contours_custom_epsg", this.state.customEpsg); this.generateReq = $.ajax({ type: 'POST', url: `/api/plugins/contours/task/${taskId}/contours/generate`, data: data }).done(result => { if (result.celery_task_id){ Workers.waitForCompletion(result.celery_task_id, error => { if (error) this.setState({[loadingProp]: false, error}); else{ const fileUrl = `/api/plugins/contours/task/${taskId}/contours/download/${result.celery_task_id}`; // Preview if (isPreview){ this.addGeoJSONFromURL(fileUrl, e => { if (e) this.setState({error: JSON.stringify(e)}); this.setState({[loadingProp]: false}); }); }else{ // Download location.href = fileUrl; this.setState({[loadingProp]: false}); } } }, `/api/plugins/contours/task/${taskId}/contours/check/`); }else if (result.error){ this.setState({[loadingProp]: false, error: result.error}); }else{ this.setState({[loadingProp]: false, error: "Invalid response: " + result}); } }).fail(error => { this.setState({[loadingProp]: false, error: JSON.stringify(error)}); }); } handleExport = (format) => { return () => { const data = this.getFormValues(); data.format = format; this.generateContours(data, 'exportLoading', false); }; } handleShowPreview = () => { this.setState({previewLoading: true}); const data = this.getFormValues(); data.epsg = 4326; data.format = "GeoJSON"; this.generateContours(data, 'previewLoading', true); } render(){ const { loading, task, layers, error, permanentError, interval, customInterval, layer, epsg, customEpsg, exportLoading, simplify, customSimplify, previewLoading, previewLayer } = this.state; const intervalValues = [0.25, 0.5, 1, 1.5, 2]; const simplifyValues = [{label: _('Do not simplify'), value: 0}, {label: _('Normal'), value: 0.2}, {label: _('Aggressive'), value: 1}]; const disabled = (interval === "custom" && !customInterval) || (epsg === "custom" && !customEpsg) || (simplify === "custom" && !customSimplify); let content = ""; if (loading) content = ( {_("Loading…")}); else if (permanentError) content = (
{permanentError}
); else{ content = (
{interval === "custom" ?
{_("meter")}
: ""}
{simplify === "custom" ?
{_("meter")}
: ""}
{epsg === "custom" ?
: ""}
{previewLayer ? : ""}
); } return (
{_("Contours")}

{content}
); } }