Modify a measure tool in qgis2web - openlayers export - add area function
Solution 1:
Take at look at this OpenLayers 6 example https://openlayers.org/en/latest/examples/measure-style.html It could probably be made to work with OpenLayers 4. Displacement for regular shapes is not supported on OL4 but you could use the regular shape image as an icon and set an anchor instead:
image: new ol.style.Icon({
src: new ol.style.RegularShape({
radius: 6,
points: 3,
angle: Math.PI,
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)'
})
}).getImage(1).toDataURL(),
anchor: [0.5, 1]
})
Update It will work in OL4 - there is a bug when cloning text styles and the overlay layers used by interactions cannot be accessed but workarounds are possibe:
<!DOCTYPE html>
<html>
<head>
<title>Measure</title>
<link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#map {
position: relative;
}
#form {
z-index: 1;
opacity: 1;
position: absolute;
bottom: 0;
left: 0;
margin: 0;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<form id="form">
<label for="type">Measurement type </label>
<select id="type">
<option value="None">None</option>
<option value="LineString">Length (LineString)</option>
<option value="Polygon">Area (Polygon)</option>
</select>
<br>
<label for="segments">Show segment lengths: </label>
<input type="checkbox" id="segments" checked />
<br>
<label for="clear">Clear previous measure: </label>
<input type="checkbox" id="clear" checked />
</form>
<script>
const typeSelect = document.getElementById('type');
const showSegments = document.getElementById('segments');
const clearPrevious = document.getElementById('clear');
const style = new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)',
}),
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.5)',
lineDash: [10, 10],
width: 2,
}),
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.7)',
}),
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)',
}),
}),
});
const labelStyle = new ol.style.Style({
text: new ol.style.Text({
font: '14px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.7)',
}),
padding: [3, 3, 3, 3],
textBaseline: 'bottom',
offsetY: -15,
}),
image: new ol.style.Icon({
src: new ol.style.RegularShape({
radius: 8,
points: 3,
angle: Math.PI,
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.7)',
}),
}).getImage(1).toDataURL(),
anchor: [0.5, 1],
}),
});
const tipStyle = new ol.style.Style({
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
padding: [2, 2, 2, 2],
textAlign: 'left',
offsetX: 15,
}),
});
const modifyStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.7)',
}),
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
}),
text: new ol.style.Text({
text: 'Drag to modify',
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.7)',
}),
padding: [2, 2, 2, 2],
textAlign: 'left',
offsetX: 15,
}),
});
const segmentStyles = [];
const formatLength = function (line) {
const length = ol.Sphere.getLength(line);
let output;
if (length > 100) {
output = Math.round((length / 1000) * 100) / 100 + ' km';
} else {
output = Math.round(length * 100) / 100 + ' m';
}
return output;
};
const formatArea = function (polygon) {
const area = ol.Sphere.getArea(polygon);
let output;
if (area > 10000) {
output = Math.round((area / 1000000) * 100) / 100 + ' km\xB2';
} else {
output = Math.round(area * 100) / 100 + ' m\xB2';
}
return output;
};
const raster = new ol.layer.Tile({
source: new ol.source.OSM(),
});
const source = new ol.source.Vector();
let modifying = false;
const modify = new ol.interaction.Modify({
source: source,
style: function() {
modifying = true;
return modifyStyle;
}
});
let tipPoint;
function styleFunction(feature, segments, drawType, tip) {
const styles = [style];
const geometry = feature.getGeometry();
const type = geometry.getType();
let point, label, line;
if (!drawType || drawType === type) {
if (type === 'Polygon') {
point = geometry.getInteriorPoint();
label = formatArea(geometry);
line = new ol.geom.LineString(geometry.getCoordinates()[0]);
} else if (type === 'LineString') {
point = new ol.geom.Point(geometry.getLastCoordinate());
label = formatLength(geometry);
line = geometry;
}
}
if (segments && line) {
let count = 0;
line.forEachSegment(function (a, b) {
const segment = new ol.geom.LineString([a, b]);
const label = formatLength(segment);
if (segmentStyles.length - 1 < count) {
segmentStyles.push(
new ol.style.Style({
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
padding: [2, 2, 2, 2],
textBaseline: 'bottom',
offsetY: -12,
}),
image: new ol.style.Icon({
src: new ol.style.RegularShape({
radius: 6,
points: 3,
angle: Math.PI,
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
}).getImage(1).toDataURL(),
anchor: [0.5, 1],
}),
})
);
}
const segmentPoint = new ol.geom.Point(segment.getCoordinateAt(0.5));
segmentStyles[count].setGeometry(segmentPoint);
segmentStyles[count].getText().setText(label);
styles.push(segmentStyles[count]);
count++;
});
}
if (label) {
labelStyle.setGeometry(point);
labelStyle.getText().setText(label);
styles.push(labelStyle);
}
if (
tip &&
type === 'Point' &&
!modifying
) {
tipPoint = geometry;
tipStyle.getText().setText(tip);
styles.push(tipStyle);
}
modifying = false;
return styles;
}
const vector = new ol.layer.Vector({
source: source,
style: function (feature) {
return styleFunction(feature, showSegments.checked);
},
});
const map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 15,
}),
});
map.addInteraction(modify);
let draw; // global so we can remove it later
function addInteraction() {
const drawType = typeSelect.value;
if (drawType == 'None') {
modify.setActive(false);
return;
}
const activeTip =
'Click to continue drawing the ' +
(drawType === 'Polygon' ? 'polygon' : 'line');
const idleTip = 'Click to start measuring';
let tip = idleTip;
draw = new ol.interaction.Draw({
source: source,
type: drawType,
style: function (feature) {
return styleFunction(feature, showSegments.checked, drawType, tip);
},
});
draw.on('drawstart', function () {
if (clearPrevious.checked) {
source.clear();
}
modify.setActive(false);
tip = activeTip;
});
draw.on('drawend', function () {
modifyStyle.setGeometry(tipPoint);
modify.setActive(true);
map.once('pointermove', function () {
modifyStyle.setGeometry();
});
tip = idleTip;
});
modify.setActive(true);
map.addInteraction(draw);
}
typeSelect.onchange = function () {
map.removeInteraction(draw);
addInteraction();
};
addInteraction();
showSegments.onchange = function () {
vector.changed();
};
</script>
</body>
</html>
To use as a control you would need to call the addInteraction
function from the comtrol's click handler function (I replaced the None option with hiding and showing the options form).
<!DOCTYPE html>
<html>
<head>
<title>Measure</title>
<link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css">
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#map {
position: relative;
}
#form {
z-index: 1;
opacity: 1;
position: absolute;
bottom: 0;
left: 0;
margin: 0;
}
.measure-control {
top: 65px;
left: .5em;
}
.ol-touch .measure-control {
top: 80px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<form id="form" style="display: none">
<label for="type">Measurement type </label>
<select id="type">
<option value="LineString">Length (LineString)</option>
<option value="Polygon">Area (Polygon)</option>
</select>
<br>
<label for="segments">Show segment lengths: </label>
<input type="checkbox" id="segments" checked />
<br>
<label for="clear">Clear previous measure: </label>
<input type="checkbox" id="clear" checked />
</form>
<script>
const typeSelectForm = document.getElementById('form');
const typeSelect = document.getElementById('type');
const showSegments = document.getElementById('segments');
const clearPrevious = document.getElementById('clear');
const style = new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)',
}),
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.5)',
lineDash: [10, 10],
width: 2,
}),
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.7)',
}),
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)',
}),
}),
});
const labelStyle = new ol.style.Style({
text: new ol.style.Text({
font: '14px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.7)',
}),
padding: [3, 3, 3, 3],
textBaseline: 'bottom',
offsetY: -15,
}),
image: new ol.style.Icon({
src: new ol.style.RegularShape({
radius: 8,
points: 3,
angle: Math.PI,
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.7)',
}),
}).getImage(1).toDataURL(),
anchor: [0.5, 1],
}),
});
const tipStyle = new ol.style.Style({
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
padding: [2, 2, 2, 2],
textAlign: 'left',
offsetX: 15,
}),
});
const modifyStyle = new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.7)',
}),
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
}),
text: new ol.style.Text({
text: 'Drag to modify',
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.7)',
}),
padding: [2, 2, 2, 2],
textAlign: 'left',
offsetX: 15,
}),
});
const segmentStyles = [];
const formatLength = function (line) {
const length = ol.Sphere.getLength(line);
let output;
if (length > 100) {
output = Math.round((length / 1000) * 100) / 100 + ' km';
} else {
output = Math.round(length * 100) / 100 + ' m';
}
return output;
};
const formatArea = function (polygon) {
const area = ol.Sphere.getArea(polygon);
let output;
if (area > 10000) {
output = Math.round((area / 1000000) * 100) / 100 + ' km\xB2';
} else {
output = Math.round(area * 100) / 100 + ' m\xB2';
}
return output;
};
const raster = new ol.layer.Tile({
source: new ol.source.OSM(),
});
const source = new ol.source.Vector();
let modifying = false;
const modify = new ol.interaction.Modify({
source: source,
style: function() {
modifying = true;
return modifyStyle;
}
});
let tipPoint;
function styleFunction(feature, segments, drawType, tip) {
const styles = [style];
const geometry = feature.getGeometry();
const type = geometry.getType();
let point, label, line;
if (!drawType || drawType === type) {
if (type === 'Polygon') {
point = geometry.getInteriorPoint();
label = formatArea(geometry);
line = new ol.geom.LineString(geometry.getCoordinates()[0]);
} else if (type === 'LineString') {
point = new ol.geom.Point(geometry.getLastCoordinate());
label = formatLength(geometry);
line = geometry;
}
}
if (segments && line) {
let count = 0;
line.forEachSegment(function (a, b) {
const segment = new ol.geom.LineString([a, b]);
const label = formatLength(segment);
if (segmentStyles.length - 1 < count) {
segmentStyles.push(
new ol.style.Style({
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 1)',
}),
backgroundFill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
padding: [2, 2, 2, 2],
textBaseline: 'bottom',
offsetY: -12,
}),
image: new ol.style.Icon({
src: new ol.style.RegularShape({
radius: 6,
points: 3,
angle: Math.PI,
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 0.4)',
}),
}).getImage(1).toDataURL(),
anchor: [0.5, 1],
}),
})
);
}
const segmentPoint = new ol.geom.Point(segment.getCoordinateAt(0.5));
segmentStyles[count].setGeometry(segmentPoint);
segmentStyles[count].getText().setText(label);
styles.push(segmentStyles[count]);
count++;
});
}
if (label) {
labelStyle.setGeometry(point);
labelStyle.getText().setText(label);
styles.push(labelStyle);
}
if (
tip &&
type === 'Point' &&
!modifying
) {
tipPoint = geometry;
tipStyle.getText().setText(tip);
styles.push(tipStyle);
}
modifying = false;
return styles;
}
const vector = new ol.layer.Vector({
source: source,
style: function (feature) {
return styleFunction(feature, showSegments.checked);
},
});
const map = new ol.Map({
layers: [raster, vector],
target: 'map',
view: new ol.View({
center: [-11000000, 4600000],
zoom: 15,
}),
});
map.addInteraction(modify);
let draw; // global so we can remove it later
function addInteraction() {
map.removeInteraction(draw);
const drawType = typeSelect.value;
if (typeSelectForm.style.display == 'none') {
modify.setActive(false);
return;
}
const activeTip =
'Click to continue drawing the ' +
(drawType === 'Polygon' ? 'polygon' : 'line');
const idleTip = 'Click to start measuring';
let tip = idleTip;
draw = new ol.interaction.Draw({
source: source,
type: drawType,
style: function (feature) {
return styleFunction(feature, showSegments.checked, drawType, tip);
},
});
draw.on('drawstart', function () {
if (clearPrevious.checked) {
source.clear();
}
modify.setActive(false);
tip = activeTip;
});
draw.on('drawend', function () {
modifyStyle.setGeometry(tipPoint);
modify.setActive(true);
map.once('pointermove', function () {
modifyStyle.setGeometry();
});
tip = idleTip;
});
modify.setActive(true);
map.addInteraction(draw);
}
typeSelect.onchange = function () {
addInteraction();
};
addInteraction();
showSegments.onchange = function () {
vector.changed();
};
var measuring = false;
var measureControl = (function (Control) {
measureControl = function(opt_options) {
var options = opt_options || {};
var button = document.createElement('button');
button.className += ' fas fa-ruler ';
var this_ = this;
var handleMeasure = function(e) {
if (!measuring) {
typeSelectForm.style.display = '';
addInteraction();
measuring = true;
} else {
typeSelectForm.style.display = 'none';
addInteraction();
measuring = false;
}
};
button.addEventListener('click', handleMeasure, false);
button.addEventListener('touchstart', handleMeasure, false);
var element = document.createElement('div');
element.className = 'measure-control ol-unselectable ol-control';
element.appendChild(button);
ol.control.Control.call(this, {
element: element,
target: options.target
});
};
if (Control) measureControl.__proto__ = Control;
measureControl.prototype = Object.create(Control && Control.prototype);
measureControl.prototype.constructor = measureControl;
return measureControl;
}(ol.control.Control));
map.addControl(new measureControl());
</script>
</body>
</html>
It seems the qgis2web code uses the variable sketch
to determine if its own measure is active (the onSingleClick
function does nothing if it is), so instead of using a new variable you could use that
sketch = false;
var measureControl = (function (Control) {
measureControl = function(opt_options) {
var options = opt_options || {};
var button = document.createElement('button');
button.className += ' fas fa-ruler ';
var this_ = this;
var handleMeasure = function(e) {
if (!sketch) {
typeSelectForm.style.display = '';
addInteraction();
sketch = true;
} else {
typeSelectForm.style.display = 'none';
addInteraction();
sketch = false;
}
};
Solution 2:
Thanks @Mike for your answer however I was unable to implement the code you provided with the qgis2web code. However, I managed to reach the goal despite having had so much difficulty given my little experience with programming (it took me 3 months). This is the result:
- clicking on the button opens a form with a request for geometry, length or area
- the drawing is a broken line with the measurement of the segments in addition to the measurement of the total
- with the double click the geometry is closed, the balloon of the total is yellow and further measurements can be carried out
- the area presents the balloon with the total in the center, maintaining the measurement of the segments
- when you change the type of geometry from length to area the measurements on the screen are reset. To completely deactivate the measurement, click again on the measurement button and all the elements on the screen will be deleted.
I describe the modified code of qgis2web: index.html
<style>
...etc...
.ol-touch .measure-control {
top: 80px;
}
#form_measure {
background-color: rgba(255, 255, 255, 0.75);
border: 3px solid #f8f8f8 !important;
z-index: 1;
opacity: 1;
position: absolute;
top: 65px;
left: 2.7em;
margin: 0;
width: 147px;
height: 19px;
}
</style>
<body>
<div id="map">
<div id="popup" class="ol-popup">
<a href="#" id="popup-closer" class="ol-popup-closer"></a>
<div id="popup-content"></div>
</div>
</div>
<form id="form_measure" style="display: none">
<label> Misura: </label>
<select id="type">
<option value="length">Lunghezza</option>
<option value="area">Area</option>
</select>
</form>
...etc...
</body>
qgis2web.js
...etc...
var handleMeasure = function(e) {
if (!measuring) {
typeSelectForm.style.display = '';
this_.getMap().addInteraction(draw);
createHelpTooltip();
createMeasureTooltip();
measuring = true;
} else {
typeSelectForm.style.display = 'none';
this_.getMap().removeInteraction(draw);
measuring = false;
this_.getMap().removeOverlay(helpTooltip);
this_.getMap().removeOverlay(measureTooltip);
var staticTooltip = document.getElementsByClassName('tooltip-static');
while(staticTooltip.length > 0){
staticTooltip[0].parentNode.removeChild(staticTooltip[0]);
}
measureLayer.getSource().clear();
}
};
...etc...
/**
* Message to show when the user is drawing a polygon.
* @type {string}
*/
var continuePolygonMsg = '1click continua, 2click chiudi';
var typeSelect = document.getElementById('type');
var typeSelectForm = document.getElementById('form_measure');
/**
* Let user change the geometry type.
* @param {Event} e Change event.
*/
typeSelect.onchange = function(e) {
typeSelectForm.style.display = 'none';
map.removeInteraction(draw);
measuring = false;
map.removeOverlay(helpTooltip);
map.removeOverlay(measureTooltip);
var staticTooltip = document.getElementsByClassName('tooltip-static');
while(staticTooltip.length > 0){
staticTooltip[0].parentNode.removeChild(staticTooltip[0]);
}
measureLayer.getSource().clear();
addInteraction();
typeSelectForm.style.display = '';
map.addInteraction(draw);
createHelpTooltip();
createMeasureTooltip();
measuring = true;
};
var style = new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(255, 204, 51)',
lineDash: [10, 10],
width: 3
}),
image: new ol.style.Circle({
radius: 5,
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 0, 0.7)'
}),
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
})
})
});
var labelStyle = new ol.style.Style({
text: new ol.style.Text({
font: '14px Calibri,sans-serif',
fill: new ol.style.Fill({
color: 'rgba(0, 0, 0, 1)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(255, 255, 255, 1)',
width: 3
})
})
});
var labelStyleCache = [];
var styleFunction = function (feature, type) {
var styles = [style];
var geometry = feature.getGeometry();
var type = geometry.getType();
var lineString;
if (!type || type === type) {
if (type === 'Polygon') {
lineString = new ol.geom.LineString(geometry.getCoordinates()[0]);
} else if (type === 'LineString') {
lineString = geometry;
}
}
if (lineString) {
var count = 0;
lineString.forEachSegment(function(a, b) {
var segment = new ol.geom.LineString([a, b]);
var label = formatLength(segment);
if (labelStyleCache.length - 1 < count) {
labelStyleCache.push(labelStyle.clone());
}
labelStyleCache[count].setGeometry(segment);
labelStyleCache[count].getText().setText(label);
styles.push(labelStyleCache[count]);
count++;
});
}
return styles;
};
var source = new ol.source.Vector();
var measureLayer = new ol.layer.Vector({
source: source,
style: function(feature) {
return styleFunction(feature);
}
});
map.addLayer(measureLayer);
var draw; // global so we can remove it later
function addInteraction() {
var type = (typeSelect.value == 'area' ? 'Polygon' : 'LineString');
draw = new ol.interaction.Draw({
source: source,
type: /** @type {ol.geom.GeometryType} */ (type),
style: function (feature) {
return styleFunction(feature, type)
}
});
var listener;
draw.on('drawstart',
function(evt) {
// set sketch
sketch = evt.feature;
/** @type {ol.Coordinate|undefined} */
var tooltipCoord = evt.coordinate;
listener = sketch.getGeometry().on('change', function(evt) {
var geom = evt.target;
var output;
if (geom instanceof ol.geom.Polygon) {
output = formatArea(/** @type {ol.geom.Polygon} */ (geom));
tooltipCoord = geom.getInteriorPoint().getCoordinates();
} else if (geom instanceof ol.geom.LineString) {
output = formatLength( /** @type {ol.geom.LineString} */ (geom));
tooltipCoord = geom.getLastCoordinate();
}
measureTooltipElement.innerHTML = output;
measureTooltip.setPosition(tooltipCoord);
});
}, this);
draw.on('drawend',
function(evt) {
measureTooltipElement.className = 'tooltip tooltip-static';
measureTooltip.setOffset([0, -7]);
// unset sketch
sketch = null;
// unset tooltip so that a new one can be created
measureTooltipElement = null;
createMeasureTooltip();
ol.Observable.unByKey(listener);
}, this);
}
...etc...
/**
* Format area output.
* @param {ol.geom.Polygon} polygon The polygon.
* @return {string} Formatted area.
*/
var formatArea = function(polygon) {
var area = polygon.getArea();
var output;
if (area > 10000) {
output = (Math.round(area / 1000000 * 100) / 100) +
' ' + 'km<sup>2</sup>';
} else {
output = (Math.round(area * 100) / 100) +
' ' + 'm<sup>2</sup>';
}
return output;
};
addInteraction();