kopia lustrzana https://github.com/OpenDroneMap/WebODM
Contours imperial preview working
rodzic
75678b7a84
commit
d76eacabd3
|
@ -18,6 +18,14 @@ class Storage{
|
|||
console.warn("Failed to call setItem " + key, e);
|
||||
}
|
||||
}
|
||||
|
||||
static removeItem(key){
|
||||
try{
|
||||
localStorage.removeItem(key);
|
||||
}catch(e){
|
||||
console.warn("Failed to call removeItem " + key, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Storage;
|
|
@ -1,112 +1,156 @@
|
|||
import { _ } from './gettext';
|
||||
|
||||
const types = {
|
||||
LENGTH: 1,
|
||||
AREA: 2,
|
||||
VOLUME: 3
|
||||
};
|
||||
|
||||
const units = {
|
||||
acres: {
|
||||
factor: (1 / (0.3048 * 0.3048)) / 43560,
|
||||
abbr: 'ac',
|
||||
round: 5
|
||||
round: 5,
|
||||
label: _("Acres"),
|
||||
type: types.AREA
|
||||
},
|
||||
acres_us: {
|
||||
factor: Math.pow(3937 / 1200, 2) / 43560,
|
||||
abbr: 'ac (US)',
|
||||
round: 5
|
||||
round: 5,
|
||||
label: _("Acres"),
|
||||
type: types.AREA
|
||||
},
|
||||
feet: {
|
||||
factor: 1 / 0.3048,
|
||||
abbr: 'ft',
|
||||
round: 4
|
||||
round: 4,
|
||||
label: _("Feet"),
|
||||
type: types.LENGTH
|
||||
},
|
||||
feet_us:{
|
||||
factor: 3937 / 1200,
|
||||
abbr: 'ft (US)',
|
||||
round: 4
|
||||
round: 4,
|
||||
label: _("Feet"),
|
||||
type: types.LENGTH
|
||||
},
|
||||
hectares: {
|
||||
factor: 0.0001,
|
||||
abbr: 'ha',
|
||||
round: 4
|
||||
round: 4,
|
||||
label: _("Hectares"),
|
||||
type: types.AREA
|
||||
},
|
||||
meters: {
|
||||
factor: 1,
|
||||
abbr: 'm',
|
||||
round: 3
|
||||
round: 3,
|
||||
label: _("Meters"),
|
||||
type: types.LENGTH
|
||||
},
|
||||
kilometers: {
|
||||
factor: 0.001,
|
||||
abbr: 'km',
|
||||
round: 5
|
||||
round: 5,
|
||||
label: _("Kilometers"),
|
||||
type: types.LENGTH
|
||||
},
|
||||
centimeters: {
|
||||
factor: 100,
|
||||
abbr: 'cm',
|
||||
round: 1
|
||||
round: 1,
|
||||
label: _("Centimeters"),
|
||||
type: types.LENGTH
|
||||
},
|
||||
miles: {
|
||||
factor: (1 / 0.3048) / 5280,
|
||||
abbr: 'mi',
|
||||
round: 5
|
||||
},
|
||||
round: 5,
|
||||
label: _("Miles"),
|
||||
type: types.LENGTH
|
||||
},
|
||||
miles_us: {
|
||||
factor: (3937 / 1200) / 5280,
|
||||
abbr: 'mi (US)',
|
||||
round: 5
|
||||
round: 5,
|
||||
label: _("Miles"),
|
||||
type: types.LENGTH
|
||||
},
|
||||
sqfeet: {
|
||||
factor: 1 / (0.3048 * 0.3048),
|
||||
abbr: 'ft²',
|
||||
round: 2
|
||||
round: 2,
|
||||
label: _("Squared Feet"),
|
||||
type: types.AREA
|
||||
},
|
||||
sqfeet_us: {
|
||||
factor: Math.pow(3937 / 1200, 2),
|
||||
abbr: 'ft² (US)',
|
||||
round: 2
|
||||
round: 2,
|
||||
label: _("Squared Feet"),
|
||||
type: types.AREA
|
||||
},
|
||||
sqmeters: {
|
||||
factor: 1,
|
||||
abbr: 'm²',
|
||||
round: 2
|
||||
round: 2,
|
||||
label: _("Squared Meters"),
|
||||
type: types.AREA
|
||||
},
|
||||
sqkilometers: {
|
||||
factor: 0.000001,
|
||||
abbr: 'km²',
|
||||
round: 5
|
||||
round: 5,
|
||||
label: _("Squared Kilometers"),
|
||||
type: types.AREA
|
||||
},
|
||||
sqmiles: {
|
||||
factor: Math.pow((1 / 0.3048) / 5280, 2),
|
||||
abbr: 'mi²',
|
||||
round: 5
|
||||
round: 5,
|
||||
label: _("Squared Miles"),
|
||||
type: types.AREA
|
||||
},
|
||||
sqmiles_us: {
|
||||
factor: Math.pow((3937 / 1200) / 5280, 2),
|
||||
abbr: 'mi² (US)',
|
||||
round: 5
|
||||
round: 5,
|
||||
label: _("Squared Miles"),
|
||||
type: types.AREA
|
||||
},
|
||||
cbmeters:{
|
||||
factor: 1,
|
||||
abbr: 'm³',
|
||||
round: 4
|
||||
round: 4,
|
||||
label: _("Cubic Meters"),
|
||||
type: types.VOLUME
|
||||
},
|
||||
cbyards:{
|
||||
factor: Math.pow(1/(0.3048*3), 3),
|
||||
abbr: 'yd³',
|
||||
round: 4
|
||||
round: 4,
|
||||
label: _("Cubic Yards"),
|
||||
type: types.VOLUME
|
||||
},
|
||||
cbyards_us:{
|
||||
factor: Math.pow(3937/3600, 3),
|
||||
abbr: 'yd³ (US)',
|
||||
round: 4
|
||||
round: 4,
|
||||
label: _("Cubic Yards"),
|
||||
type: types.VOLUME
|
||||
}
|
||||
};
|
||||
|
||||
class ValueUnit{
|
||||
constructor(val, unit){
|
||||
this.val = val;
|
||||
constructor(value, unit){
|
||||
this.value = value;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
toString(){
|
||||
const mul = Math.pow(10, this.unit.round);
|
||||
const rounded = (Math.round(this.val * mul) / mul).toString();
|
||||
const rounded = (Math.round(this.value * mul) / mul).toString();
|
||||
|
||||
let withCommas = "";
|
||||
let parts = rounded.split(".");
|
||||
|
@ -117,6 +161,12 @@ class ValueUnit{
|
|||
}
|
||||
}
|
||||
|
||||
class NanUnit{
|
||||
toString(){
|
||||
return "NaN";
|
||||
}
|
||||
}
|
||||
|
||||
class UnitSystem{
|
||||
lengthUnit(meters){ throw new Error("Not implemented"); }
|
||||
areaUnit(sqmeters){ throw new Error("Not implemented"); }
|
||||
|
@ -125,24 +175,55 @@ class UnitSystem{
|
|||
getName(){ throw new Error("Not implemented"); }
|
||||
|
||||
area(sqmeters){
|
||||
sqmeters = parseFloat(sqmeters);
|
||||
if (isNaN(sqmeters)) return NanUnit();
|
||||
|
||||
const unit = this.areaUnit(sqmeters);
|
||||
const val = unit.factor * sqmeters;
|
||||
return new ValueUnit(val, unit);
|
||||
}
|
||||
|
||||
length(meters){
|
||||
meters = parseFloat(meters);
|
||||
if (isNaN(meters)) return NanUnit();
|
||||
|
||||
const unit = this.lengthUnit(meters);
|
||||
const val = unit.factor * meters;
|
||||
return new ValueUnit(val, unit);
|
||||
}
|
||||
|
||||
volume(cbmeters){
|
||||
cbmeters = parseFloat(cbmeters);
|
||||
if (isNaN(cbmeters)) return NanUnit();
|
||||
|
||||
const unit = this.volumeUnit(cbmeters);
|
||||
const val = unit.factor * cbmeters;
|
||||
return new ValueUnit(val, unit);
|
||||
}
|
||||
};
|
||||
|
||||
function toMetric(valueUnit, unit){
|
||||
let value = NaN;
|
||||
if (typeof valueUnit === "object" && unit === undefined){
|
||||
value = valueUnit.value;
|
||||
unit = valueUnit.unit;
|
||||
}else{
|
||||
value = parseFloat(valueUnit);
|
||||
}
|
||||
if (isNaN(value)) return NanUnit();
|
||||
|
||||
const val = value / unit.factor;
|
||||
if (unit.type === types.LENGTH){
|
||||
return new ValueUnit(val, units.meters);
|
||||
}else if (unit.type === types.AREA){
|
||||
return new ValueUnit(val, unit.sqmeters);
|
||||
}else if (unit.type === types.VOLUME){
|
||||
return new ValueUnit(val, unit.cbmeters);
|
||||
}else{
|
||||
throw new Error(`Unrecognized unit type: ${unit.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
class MetricSystem extends UnitSystem{
|
||||
getName(){
|
||||
return _("Metric");
|
||||
|
@ -249,16 +330,32 @@ const systems = {
|
|||
}
|
||||
|
||||
// Expose to allow every part of the app to access this information
|
||||
function getPreferredUnitSystem(){
|
||||
return localStorage.getItem("preferred_unit_system") || "metric";
|
||||
function getUnitSystem(){
|
||||
return localStorage.getItem("_unit_system") || "metric";
|
||||
}
|
||||
function setPreferredUnitSystem(system){
|
||||
localStorage.setItem("preferred_unit_system", system);
|
||||
function setUnitSystem(system){
|
||||
let prevSystem = getUnitSystem();
|
||||
localStorage.setItem("_unit_system", system);
|
||||
if (prevSystem !== system){
|
||||
document.dispatchEvent(new CustomEvent("onUnitSystemChanged", { detail: system }));
|
||||
}
|
||||
}
|
||||
|
||||
function onUnitSystemChanged(callback){
|
||||
document.addEventListener("onUnitSystemChanged", callback);
|
||||
}
|
||||
|
||||
function offUnitSystemChanged(callback){
|
||||
document.removeEventListener("onUnitSystemChanged", callback);
|
||||
}
|
||||
|
||||
export {
|
||||
systems,
|
||||
getPreferredUnitSystem,
|
||||
setPreferredUnitSystem
|
||||
types,
|
||||
toMetric,
|
||||
getUnitSystem,
|
||||
setUnitSystem,
|
||||
onUnitSystemChanged,
|
||||
offUnitSystemChanged
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { systems, getPreferredUnitSystem, setPreferredUnitSystem } from '../classes/Units';
|
||||
import { systems, getUnitSystem, setUnitSystem } from '../classes/Units';
|
||||
import '../css/UnitSelector.scss';
|
||||
|
||||
class UnitSelector extends React.Component {
|
||||
|
@ -11,13 +11,13 @@ class UnitSelector extends React.Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
system: getPreferredUnitSystem()
|
||||
system: getUnitSystem()
|
||||
}
|
||||
}
|
||||
|
||||
handleChange = e => {
|
||||
this.setState({system: e.target.value});
|
||||
setPreferredUnitSystem(e.target.value);
|
||||
setUnitSystem(e.target.value);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { systems } from '../../classes/Units';
|
||||
import { systems, toMetric } from '../../classes/Units';
|
||||
|
||||
describe('Metric system', () => {
|
||||
it('it should display units properly', () => {
|
||||
|
@ -94,5 +94,25 @@ describe('Imperial systems', () => {
|
|||
expect(imperial.volume(v[0]).toString()).toBe(v[1]);
|
||||
expect(imperialUS.volume(v[0]).toString()).toBe(v[2]);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Metric conversion', () => {
|
||||
it('it should convert units properly', () => {
|
||||
const { metric, imperial } = systems;
|
||||
|
||||
const km = metric.length(2000);
|
||||
const mi = imperial.length(3220);
|
||||
|
||||
expect(km.unit.abbr).toBe("km");
|
||||
expect(km.value).toBe(2);
|
||||
expect(mi.unit.abbr).toBe("mi");
|
||||
expect(Math.round(mi.value)).toBe(2)
|
||||
|
||||
expect(toMetric(km).toString()).toBe("2,000 m");
|
||||
expect(toMetric(mi).toString()).toBe("3,220 m");
|
||||
|
||||
expect(toMetric(km).value).toBe(2000);
|
||||
expect(toMetric(mi).value).toBe(3220);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "Contours",
|
||||
"webodmMinVersion": "0.9.0",
|
||||
"webodmMinVersion": "2.4.3",
|
||||
"description": "Compute, preview and export contours from DEMs",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"author": "Piero Toffanin",
|
||||
"email": "pt@masseranolabs.com",
|
||||
"repository": "https://github.com/OpenDroneMap/WebODM",
|
||||
|
|
|
@ -6,6 +6,7 @@ import './ContoursPanel.scss';
|
|||
import ErrorMessage from 'webodm/components/ErrorMessage';
|
||||
import Workers from 'webodm/classes/Workers';
|
||||
import { _ } from 'webodm/classes/gettext';
|
||||
import { systems, getUnitSystem, onUnitSystemChanged, offUnitSystemChanged, toMetric } from 'webodm/classes/Units';
|
||||
|
||||
export default class ContoursPanel extends React.Component {
|
||||
static defaultProps = {
|
||||
|
@ -20,13 +21,23 @@ export default class ContoursPanel extends React.Component {
|
|||
constructor(props){
|
||||
super(props);
|
||||
|
||||
const unitSystem = getUnitSystem();
|
||||
const defaultInterval = unitSystem === "metric" ? "1" : "4";
|
||||
const defaultSimplify = unitSystem === "metric" ? "0.2" : "0.6";
|
||||
|
||||
// Remove legacy parameters
|
||||
Storage.removeItem("last_contours_interval");
|
||||
Storage.removeItem("last_contours_custom_interval");
|
||||
Storage.removeItem("last_contours_simplify");
|
||||
Storage.removeItem("last_contours_custom_simplify");
|
||||
|
||||
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",
|
||||
interval: Storage.getItem("last_contours_interval_" + unitSystem) || defaultInterval,
|
||||
customInterval: Storage.getItem("last_contours_custom_interval_" + unitSystem) || defaultInterval,
|
||||
simplify: Storage.getItem("last_contours_simplify_" + unitSystem) || defaultSimplify,
|
||||
customSimplify: Storage.getItem("last_contours_custom_simplify_" + unitSystem) || defaultSimplify,
|
||||
layer: "",
|
||||
epsg: Storage.getItem("last_contours_epsg") || "4326",
|
||||
customEpsg: Storage.getItem("last_contours_custom_epsg") || "4326",
|
||||
|
@ -36,13 +47,18 @@ export default class ContoursPanel extends React.Component {
|
|||
previewLoading: false,
|
||||
exportLoading: false,
|
||||
previewLayer: null,
|
||||
unitSystem
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
onUnitSystemChanged(this.unitsChanged);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -76,6 +92,24 @@ export default class ContoursPanel extends React.Component {
|
|||
this.generateReq.abort();
|
||||
this.generateReq = null;
|
||||
}
|
||||
|
||||
offUnitSystemChanged(this.unitsChanged);
|
||||
}
|
||||
|
||||
unitsChanged = e => {
|
||||
this.saveInputValues();
|
||||
|
||||
const unitSystem = e.detail;
|
||||
|
||||
const defaultInterval = unitSystem === "metric" ? "1" : "4";
|
||||
const defaultSimplify = unitSystem === "metric" ? "0.2" : "0.5";
|
||||
|
||||
const interval = Storage.getItem("last_contours_interval_" + unitSystem) || defaultInterval;
|
||||
const customInterval = Storage.getItem("last_contours_custom_interval_" + unitSystem) || defaultInterval;
|
||||
const simplify = Storage.getItem("last_contours_simplify_" + unitSystem) || defaultSimplify;
|
||||
const customSimplify = Storage.getItem("last_contours_custom_simplify_" + unitSystem) || defaultSimplify;
|
||||
|
||||
this.setState({unitSystem, interval, customInterval, simplify, customSimplify });
|
||||
}
|
||||
|
||||
handleSelectInterval = e => {
|
||||
|
@ -108,17 +142,29 @@ export default class ContoursPanel extends React.Component {
|
|||
|
||||
getFormValues = () => {
|
||||
const { interval, customInterval, epsg, customEpsg,
|
||||
simplify, customSimplify, layer } = this.state;
|
||||
simplify, customSimplify, layer, unitSystem } = this.state;
|
||||
const su = systems[unitSystem];
|
||||
|
||||
let meterInterval = interval !== "custom" ? interval : customInterval;
|
||||
let meterSimplify = simplify !== "custom" ? simplify : customSimplify;
|
||||
|
||||
meterInterval = toMetric(meterInterval, su.lengthUnit(1)).value;
|
||||
meterSimplify = toMetric(meterSimplify, su.lengthUnit(1)).value;
|
||||
|
||||
const zExportFactor = su.lengthUnit(1).factor;
|
||||
|
||||
return {
|
||||
interval: interval !== "custom" ? interval : customInterval,
|
||||
interval: meterInterval,
|
||||
epsg: epsg !== "custom" ? epsg : customEpsg,
|
||||
simplify: simplify !== "custom" ? simplify : customSimplify,
|
||||
simplify: meterSimplify,
|
||||
zExportFactor,
|
||||
layer
|
||||
};
|
||||
}
|
||||
|
||||
addGeoJSONFromURL = (url, cb) => {
|
||||
const { map } = this.props;
|
||||
const us = systems[this.state.unitSystem];
|
||||
|
||||
$.getJSON(url)
|
||||
.done((geojson) => {
|
||||
|
@ -128,7 +174,7 @@ export default class ContoursPanel extends React.Component {
|
|||
this.setState({previewLayer: L.geoJSON(geojson, {
|
||||
onEachFeature: (feature, layer) => {
|
||||
if (feature.properties && feature.properties.level !== undefined) {
|
||||
layer.bindPopup(`<b>${_("Elevation:")}</b> ${feature.properties.level} ${_("meters")}`);
|
||||
layer.bindPopup(`<div style="margin-right: 32px;"><b>${_("Elevation:")}</b> ${us.length(feature.properties.level)}</div>`);
|
||||
}
|
||||
},
|
||||
style: feature => {
|
||||
|
@ -155,18 +201,23 @@ export default class ContoursPanel extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
saveInputValues = () => {
|
||||
const us = this.state.unitSystem;
|
||||
|
||||
// Save settings
|
||||
Storage.setItem("last_contours_interval_" + us, this.state.interval);
|
||||
Storage.setItem("last_contours_custom_interval_" + us, this.state.customInterval);
|
||||
Storage.setItem("last_contours_simplify_" + us, this.state.simplify);
|
||||
Storage.setItem("last_contours_custom_simplify_" + us, this.state.customSimplify);
|
||||
Storage.setItem("last_contours_epsg", this.state.epsg);
|
||||
Storage.setItem("last_contours_custom_epsg", this.state.customEpsg);
|
||||
}
|
||||
|
||||
generateContours = (data, loadingProp, isPreview) => {
|
||||
this.setState({[loadingProp]: true, error: ""});
|
||||
const taskId = this.state.task.id;
|
||||
this.saveInputValues();
|
||||
|
||||
// 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`,
|
||||
|
@ -222,11 +273,15 @@ export default class ContoursPanel extends React.Component {
|
|||
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];
|
||||
previewLoading, previewLayer, unitSystem } = this.state;
|
||||
const us = systems[unitSystem];
|
||||
const lengthUnit = us.lengthUnit(1);
|
||||
|
||||
const intervalStart = unitSystem === "metric" ? 1 : 4;
|
||||
const intervalValues = [intervalStart / 4, intervalStart / 2, intervalStart, intervalStart * 2, intervalStart * 4];
|
||||
const simplifyValues = [{label: _('Do not simplify'), value: 0},
|
||||
{label: _('Normal'), value: 0.2},
|
||||
{label: _('Aggressive'), value: 1}];
|
||||
{label: _('Normal'), value: unitSystem === "metric" ? 0.2 : 0.5},
|
||||
{label: _('Aggressive'), value: unitSystem === "metric" ? 1 : 4}];
|
||||
|
||||
const disabled = (interval === "custom" && !customInterval) ||
|
||||
(epsg === "custom" && !customEpsg) ||
|
||||
|
@ -242,7 +297,7 @@ export default class ContoursPanel extends React.Component {
|
|||
<label className="col-sm-3 control-label">{_("Interval:")}</label>
|
||||
<div className="col-sm-9 ">
|
||||
<select className="form-control" value={interval} onChange={this.handleSelectInterval}>
|
||||
{intervalValues.map(iv => <option value={iv}>{iv} {_("meter")}</option>)}
|
||||
{intervalValues.map(iv => <option value={iv}>{iv} {lengthUnit.label}</option>)}
|
||||
<option value="custom">{_("Custom")}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -251,7 +306,7 @@ export default class ContoursPanel extends React.Component {
|
|||
<div className="row form-group form-inline">
|
||||
<label className="col-sm-3 control-label">{_("Value:")}</label>
|
||||
<div className="col-sm-9 ">
|
||||
<input type="number" className="form-control custom-interval" value={customInterval} onChange={this.handleChangeCustomInterval} /><span> {_("meter")}</span>
|
||||
<input type="number" className="form-control custom-interval" value={customInterval} onChange={this.handleChangeCustomInterval} /><span> {lengthUnit.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
: ""}
|
||||
|
@ -269,7 +324,7 @@ export default class ContoursPanel extends React.Component {
|
|||
<label className="col-sm-3 control-label">{_("Simplify:")}</label>
|
||||
<div className="col-sm-9 ">
|
||||
<select className="form-control" value={simplify} onChange={this.handleSelectSimplify}>
|
||||
{simplifyValues.map(sv => <option value={sv.value}>{sv.label} ({sv.value} {_("meter")})</option>)}
|
||||
{simplifyValues.map(sv => <option value={sv.value}>{sv.label} ({sv.value} {lengthUnit.label})</option>)}
|
||||
<option value="custom">{_("Custom")}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
@ -278,7 +333,7 @@ export default class ContoursPanel extends React.Component {
|
|||
<div className="row form-group form-inline">
|
||||
<label className="col-sm-3 control-label">{_("Value:")}</label>
|
||||
<div className="col-sm-9 ">
|
||||
<input type="number" className="form-control custom-interval" value={customSimplify} onChange={this.handleChangeCustomSimplify} /><span> {_("meter")}</span>
|
||||
<input type="number" className="form-control custom-interval" value={customSimplify} onChange={this.handleChangeCustomSimplify} /><span> {lengthUnit.label}</span>
|
||||
</div>
|
||||
</div>
|
||||
: ""}
|
||||
|
|
Ładowanie…
Reference in New Issue