I found this article on this same site Labeling the length of each side of polygon openlayers 3 I also use qgis2web, export openlayers. I would like to use his code to add the "measure area" function without deleting the existing "measure length" function. Thanks.
qgis2web.js (with only area measurement)
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) {
this_.getMap().addInteraction(draw);
createHelpTooltip();
createMeasureTooltip();
measuring = true;
} else {
this_.getMap().removeInteraction(draw);
measuring = false;
this_.getMap().removeOverlay(helpTooltip);
this_.getMap().removeOverlay(measureTooltip);
}
};
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));
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');
var sketch;
closer.onclick = function() {
container.style.display = 'none';
closer.blur();
return false;
};
var overlayPopup = new ol.Overlay({
element: container
});
var expandedAttribution = new ol.control.Attribution({
collapsible: false
});
var map = new ol.Map({
controls: ol.control.defaults({attribution:false}).extend([
expandedAttribution,new ol.control.ScaleLine({}),new measureControl()
]),
target: document.getElementById('map'),
renderer: 'canvas',
overlays: [overlayPopup],
layers: layersList,
view: new ol.View({
extent: [2283125.045170, 4809940.953436, 2383123.537919, 4874627.954073], maxZoom: 28, minZoom: 1, projection: new ol.proj.Projection({
code: 'EPSG:3004',
extent: [-20037508.342789, -20037508.342789, 20037508.342789, 20037508.342789],
units: 'm'})
})
});
var layerSwitcher = new ol.control.LayerSwitcher({tipLabel: "Layers"});
map.addControl(layerSwitcher);
map.getView().fit([2283125.045170, 4809940.953436, 2383123.537919, 4874627.954073], map.getSize());
var NO_POPUP = 0
var ALL_FIELDS = 1
/**
* Returns either NO_POPUP, ALL_FIELDS or the name of a single field to use for
* a given layer
* @param layerList {Array} List of ol.Layer instances
* @param layer {ol.Layer} Layer to find field info about
*/
function getPopupFields(layerList, layer) {
// Determine the index that the layer will have in the popupLayers Array,
// if the layersList contains more items than popupLayers then we need to
// adjust the index to take into account the base maps group
var idx = layersList.indexOf(layer) - (layersList.length - popupLayers.length);
return popupLayers[idx];
}
var collection = new ol.Collection();
var featureOverlay = new ol.layer.Vector({
map: map,
source: new ol.source.Vector({
features: collection,
useSpatialIndex: false // optional, might improve performance
}),
style: [new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#f00',
width: 1
}),
fill: new ol.style.Fill({
color: 'rgba(255,0,0,0.1)'
}),
})],
updateWhileAnimating: true, // optional, for instant visual feedback
updateWhileInteracting: true // optional, for instant visual feedback
});
var doHighlight = false;
var doHover = false;
var highlight;
var autolinker = new Autolinker({truncate: {length: 30, location: 'smart'}});
var onPointerMove = function(evt) {
if (!doHover && !doHighlight) {
return;
}
var pixel = map.getEventPixel(evt.originalEvent);
var coord = evt.coordinate;
var popupField;
var currentFeature;
var currentLayer;
var currentFeatureKeys;
var clusteredFeatures;
var popupText = '<ul>';
map.forEachFeatureAtPixel(pixel, function(feature, layer) {
// We only care about features from layers in the layersList, ignore
// any other layers which the map might contain such as the vector
// layer used by the measure tool
if (layersList.indexOf(layer) === -1) {
return;
}
var doPopup = false;
for (k in layer.get('fieldImages')) {
if (layer.get('fieldImages')[k] != "Hidden") {
doPopup = true;
}
}
currentFeature = feature;
currentLayer = layer;
clusteredFeatures = feature.get("features");
var clusterFeature;
if (typeof clusteredFeatures !== "undefined") {
if (doPopup) {
for(var n=0; n<clusteredFeatures.length; n++) {
clusterFeature = clusteredFeatures[n];
currentFeatureKeys = clusterFeature.getKeys();
popupText += '<li><table>'
for (var i=0; i<currentFeatureKeys.length; i++) {
if (currentFeatureKeys[i] != 'geometry') {
popupField = '';
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label") {
popupField += '<th>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</th><td>';
} else {
popupField += '<td colspan="2">';
}
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label") {
popupField += '<strong>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</strong><br />';
}
if (layer.get('fieldImages')[currentFeatureKeys[i]] != "ExternalResource") {
popupField += (clusterFeature.get(currentFeatureKeys[i]) != null ? autolinker.link(clusterFeature.get(currentFeatureKeys[i]).toLocaleString()) + '</td>' : '');
} else {
popupField += (clusterFeature.get(currentFeatureKeys[i]) != null ? '<img src="images/' + clusterFeature.get(currentFeatureKeys[i]).replace(/[\\\/:]/g, '_').trim() + '" /></td>' : '');
}
popupText += '<tr>' + popupField + '</tr>';
}
}
popupText += '</table></li>';
}
}
} else {
currentFeatureKeys = currentFeature.getKeys();
if (doPopup) {
popupText += '<li><table>';
for (var i=0; i<currentFeatureKeys.length; i++) {
if (currentFeatureKeys[i] != 'geometry') {
popupField = '';
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label") {
popupField += '<th>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</th><td>';
} else {
popupField += '<td colspan="2">';
}
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label") {
popupField += '<strong>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</strong><br />';
}
if (layer.get('fieldImages')[currentFeatureKeys[i]] != "ExternalResource") {
popupField += (currentFeature.get(currentFeatureKeys[i]) != null ? autolinker.link(currentFeature.get(currentFeatureKeys[i]).toLocaleString()) + '</td>' : '');
} else {
popupField += (currentFeature.get(currentFeatureKeys[i]) != null ? '<img src="images/' + currentFeature.get(currentFeatureKeys[i]).replace(/[\\\/:]/g, '_').trim() + '" /></td>' : '');
}
popupText += '<tr>' + popupField + '</tr>';
}
}
popupText += '</table></li>';
}
}
});
if (popupText == '<ul>') {
popupText = '';
} else {
popupText += '</ul>';
}
if (doHighlight) {
if (currentFeature !== highlight) {
if (highlight) {
featureOverlay.getSource().removeFeature(highlight);
}
if (currentFeature) {
var styleDefinition = currentLayer.getStyle().toString();
if (currentFeature.getGeometry().getType() == 'Point') {
var radius = styleDefinition.split('radius')[1].split(' ')[1];
highlightStyle = new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: "#ffff00"
}),
radius: radius
})
})
} else if (currentFeature.getGeometry().getType() == 'LineString') {
var featureWidth = styleDefinition.split('width')[1].split(' ')[1].replace('})','');
highlightStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#ffff00',
lineDash: null,
width: featureWidth
})
});
} else {
highlightStyle = new ol.style.Style({
fill: new ol.style.Fill({
color: '#ffff00'
})
})
}
featureOverlay.getSource().addFeature(currentFeature);
featureOverlay.setStyle(highlightStyle);
}
highlight = currentFeature;
}
}
if (doHover) {
if (popupText) {
overlayPopup.setPosition(coord);
content.innerHTML = popupText;
container.style.display = 'block';
} else {
container.style.display = 'none';
closer.blur();
}
}
};
var onSingleClick = function(evt) {
if (doHover) {
return;
}
if (sketch) {
return;
}
var pixel = map.getEventPixel(evt.originalEvent);
var coord = evt.coordinate;
var popupField;
var currentFeature;
var currentFeatureKeys;
var clusteredFeatures;
var popupText = '<ul>';
map.forEachFeatureAtPixel(pixel, function(feature, layer) {
if (feature instanceof ol.Feature && (layer.get("interactive") || layer.get("interactive") == undefined)) {
var doPopup = false;
for (k in layer.get('fieldImages')) {
if (layer.get('fieldImages')[k] != "Hidden") {
doPopup = true;
}
}
currentFeature = feature;
clusteredFeatures = feature.get("features");
var clusterFeature;
if (typeof clusteredFeatures !== "undefined") {
if (doPopup) {
for(var n=0; n<clusteredFeatures.length; n++) {
clusterFeature = clusteredFeatures[n];
currentFeatureKeys = clusterFeature.getKeys();
popupText += '<li><table>'
for (var i=0; i<currentFeatureKeys.length; i++) {
if (currentFeatureKeys[i] != 'geometry') {
popupField = '';
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label") {
popupField += '<th>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</th><td>';
} else {
popupField += '<td colspan="2">';
}
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label") {
popupField += '<strong>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</strong><br />';
}
if (layer.get('fieldImages')[currentFeatureKeys[i]] != "ExternalResource") {
popupField += (clusterFeature.get(currentFeatureKeys[i]) != null ? autolinker.link(clusterFeature.get(currentFeatureKeys[i]).toLocaleString()) + '</td>' : '');
} else {
popupField += (clusterFeature.get(currentFeatureKeys[i]) != null ? '<img src="images/' + clusterFeature.get(currentFeatureKeys[i]).replace(/[\\\/:]/g, '_').trim() + '" /></td>' : '');
}
popupText += '<tr>' + popupField + '</tr>';
}
}
popupText += '</table></li>';
}
}
} else {
currentFeatureKeys = currentFeature.getKeys();
if (doPopup) {
popupText += '<li><table>';
for (var i=0; i<currentFeatureKeys.length; i++) {
if (currentFeatureKeys[i] != 'geometry') {
popupField = '';
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "inline label") {
popupField += '<th>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</th><td>';
} else {
popupField += '<td colspan="2">';
}
if (layer.get('fieldLabels')[currentFeatureKeys[i]] == "header label") {
popupField += '<strong>' + layer.get('fieldAliases')[currentFeatureKeys[i]] + ':</strong><br />';
}
if (layer.get('fieldImages')[currentFeatureKeys[i]] != "ExternalResource") {
popupField += (currentFeature.get(currentFeatureKeys[i]) != null ? autolinker.link(currentFeature.get(currentFeatureKeys[i]).toLocaleString()) + '</td>' : '');
} else {
popupField += (currentFeature.get(currentFeatureKeys[i]) != null ? '<img src="images/' + currentFeature.get(currentFeatureKeys[i]).replace(/[\\\/:]/g, '_').trim() + '" /></td>' : '');
}
popupText += '<tr>' + popupField + '</tr>';
}
}
popupText += '</table>';
}
}
}
});
if (popupText == '<ul>') {
popupText = '';
} else {
popupText += '</ul>';
}
var viewProjection = map.getView().getProjection();
var viewResolution = map.getView().getResolution();
for (i = 0; i < wms_layers.length; i++) {
if (wms_layers[i][1]) {
var url = wms_layers[i][0].getSource().getGetFeatureInfoUrl(
evt.coordinate, viewResolution, viewProjection,
{
'INFO_FORMAT': 'text/html',
});
if (url) {
popupText = popupText + '<iframe style="width:100%;height:110px;border:0px;" id="iframe" seamless src="' + url + '"></iframe>';
}
}
}
if (popupText) {
overlayPopup.setPosition(coord);
content.innerHTML = popupText;
container.style.display = 'block';
} else {
container.style.display = 'none';
closer.blur();
}
};
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
if (measuring) {
/** @type {string} */
var helpMsg = 'Click to start drawing';
if (sketch) {
var geom = (sketch.getGeometry());
if (geom instanceof ol.geom.Polygon) {
helpMsg = continuePolygonMsg;
} else if (geom instanceof ol.geom.LineString) {
helpMsg = continueLineMsg;
}
}
helpTooltipElement.innerHTML = helpMsg;
helpTooltip.setPosition(evt.coordinate);
}
});
map.on('pointermove', function(evt) {
onPointerMove(evt);
});
map.on('singleclick', function(evt) {
onSingleClick(evt);
});
/**
* Currently drawn feature.
* @type {ol.Feature}
*/
/**
* The help tooltip element.
* @type {Element}
*/
var helpTooltipElement;
/**
* Overlay to show the help messages.
* @type {ol.Overlay}
*/
var helpTooltip;
/**
* The measure tooltip element.
* @type {Element}
*/
var measureTooltipElement;
/**
* Overlay to show the measurement.
* @type {ol.Overlay}
*/
var measureTooltip;
/**
* Message to show when the user is drawing a polygon.
* @type {string}
*/
var continuePolygonMsg = 'Click to continue drawing the polygon';
var source = new ol.source.Vector();
var measureLayer = new ol.layer.Vector({
source: source,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new ol.style.Stroke({
color: '#ffcc33',
width: 3
}),
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({
color: '#ffcc33'
})
})
})
});
map.addLayer(measureLayer);
var draw; // global so we can remove it later
function addInteraction() {
var type = 'Polygon';
draw = new ol.interaction.Draw({
source: source,
type: /** @type {ol.geom.GeometryType} */ (type),
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)'
})
})
})
});
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;
output = formatArea(geom);
tooltipCoord = geom.getInteriorPoint().getCoordinates();
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);
}
/**
* Creates a new help tooltip
*/
function createHelpTooltip() {
if (helpTooltipElement) {
helpTooltipElement.parentNode.removeChild(helpTooltipElement);
}
helpTooltipElement = document.createElement('div');
helpTooltipElement.className = 'tooltip hidden';
helpTooltip = new ol.Overlay({
element: helpTooltipElement,
offset: [15, 0],
positioning: 'center-left'
});
map.addOverlay(helpTooltip);
}
/**
* Creates a new measure tooltip
*/
function createMeasureTooltip() {
if (measureTooltipElement) {
measureTooltipElement.parentNode.removeChild(measureTooltipElement);
}
measureTooltipElement = document.createElement('div');
measureTooltipElement.className = 'tooltip tooltip-measure';
measureTooltip = new ol.Overlay({
element: measureTooltipElement,
offset: [0, -15],
positioning: 'bottom-center'
});
map.addOverlay(measureTooltip);
}
/**
* 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();
var geocoder = new Geocoder('nominatim', {
provider: 'osm',
lang: 'en-US',
placeholder: 'Search for ...',
limit: 5,
keepOpen: true
});
map.addControl(geocoder);
document.getElementsByClassName('gcd-gl-btn')[0].className += ' fa fa-search';
var attributionComplete ......ecc...
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:
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();
sketch = null;
}
};
...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();