OpenLayers3. Измерение дистанции и площади.

Mapserver, GeoServer, MapGuide, Google и другое ПО для веб-картографии
Ответить
Warden
Интересующийся
Сообщения: 25
Зарегистрирован: 16 сен 2015, 16:43
Репутация: 7
Откуда: Королёв

OpenLayers3. Измерение дистанции и площади.

Сообщение Warden » 02 окт 2015, 09:44

Эта тема направлена не на поиск ответа, а скорее на помощь тем, кто будет пытаться решить схожую задачу.
В общем, у нас есть подложка OSM и пару WMS слоев, с которыми может взаимодействовать popup и мы создаем векторный слой для рисований линий и полигонов и сразу происходит расчет измерений взятый с example. Также я добавил стиралку для нарисованных features. (код html)

Код: Выделить всё

<div id='map'>
    </div>
    <div id='bar'>
      <p id='hand'>
        <img src="img/hand.png">
      </p>
      <p id='drawLine'>
        <img src="img/line.png">
      </p>
      <p id='drawPoly'>
        <img src="img/poly.png">
      </p>
      <p id='edit'>
        <img src="img/edit.png">
      </p>
      <p id='erase'>
        <img src="img/erase.png">
      </p>
      </div>
(код js):

Код: Выделить всё

 drawSource = new ol.source.Vector();

	 drawLayer = new ol.layer.Vector({
		source: drawSource,
		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: 2
	    	}),
    		image: new ol.style.Circle({
		    	radius: 7,
		      	fill: new ol.style.Fill({
		        	color: '#ffcc33'
		      	})
    		})
  		})
	});
 ***

	var select = new ol.interaction.Select();
	var erase = new ol.interaction.Select();

	var lineDraw = new ol.interaction.Draw({
		source: drawSource,
		type: 'LineString',
		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 polyDraw = new ol.interaction.Draw({
		source: drawSource,
		type: 'Polygon',
		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 measureTooltipElement;
	var measureTooltip;
	createMeasureTooltip();
	var sketch;
	var listener;
	lineDraw.on('drawstart', function(evt){
    	sketch = evt.feature;
		var tooltipCoord = evt.coordinate;
		listener = sketch.getGeometry().on('change', function(evt) {
          var geom = evt.target;
          var output;
          output = formatLength((geom));
          tooltipCoord = geom.getLastCoordinate();
          measureTooltipElement.innerHTML = output;
          measureTooltip.setPosition(tooltipCoord);
        });
      }, this);

  	lineDraw.on('drawend', function(evt){
        measureTooltipElement.className = 'tooltip tooltip-static';
        measureTooltip.setOffset([0, -7]);
        sketch = null;
        measureTooltipElement = null;
        createMeasureTooltip();
        ol.Observable.unByKey(listener);
    }, this);

***

	$("#drawLine").click(function() {
		clearCustomInteractions();
		$(this).addClass('active');
		map.addInteraction(lineDraw);
	});

	$("#drawPoly").click(function() {
		clearCustomInteractions();
		$(this).addClass('active');
		map.addInteraction(polyDraw);
	});

$("#erase").click(function() {
		clearCustomInteractions();
		$(this).addClass('active');
		map.addInteraction(erase);

		erase.getFeatures().on('change:length', function(e){

			if(e.target.getArray().length  !== 0) {
				drawLayer.getSource().removeFeature(e.target.item(0));
				}
		});
И вот тут появилась проблема: я могу стереть features, но как стереть measureTooltip. Стереть все overlay нельзя, так как тогда пропадет и popup, да и не охота чтобы при стирании одной линии стирались все окна измерений. Я долго ломал голову как связать созданную линию и окно измерений. Я много что попробовал для решений этой задачи. Даже пытался создать closer для measureTooltip как для popupа, но не мог их связать. Решение простое до невозможности, но наверное в силу моей небольшой практики с JavaScript я не сразу до него дошел.
В общем, в один из мозговых штурмов появилась идея: а что если узнать номер индекса выделенного элемента, когда используется erase? И опять же моя небольшая пркатика с этим языком программирования заставила меня помучиться. Цель стала ясна, нужно выделенный элемент при помощи erase сравнить с массивом features из векторного слоя, найти этот номер и удалить overlay = индекс feature + 1 (у нас же в оверлеи как минимум есть popup). В общем задача была решена простым способом:

Код: Выделить всё

$("#erase").click(function() {
		clearCustomInteractions();
		$(this).addClass('active');
		map.addInteraction(erase);

		erase.getFeatures().on('change:length', function(e){

			if(e.target.getArray().length  !== 0) {
				var i = e.target.item(0);
				var k = drawLayer.getSource().getFeatures();
				var j = k.indexOf(i);			
				drawLayer.getSource().removeFeature(e.target.item(0));
				delOverlay = map.getOverlays().array_[j+1];
  				map.removeOverlay(delOverlay);
			}
		});
Надеюсь я Вам не наскучил. У кого есть более изящные или простые решения, м.б. связка оверлея и линии при создания, пожалуйста дайте знать. Я не верю, что у этой задачи нету более простого решения! :D

MichaelK
Новоприбывший
Сообщения: 14
Зарегистрирован: 19 июн 2012, 23:28
Репутация: 5

Re: OpenLayers3. Измерение дистанции и площади.

Сообщение MichaelK » 05 окт 2015, 11:43

Можно, например, overlay прямо в линию запихнуть

Код: Выделить всё

Там где lineDraw.on('drawend', function(evt){ ...
evt.feature.set('measureTooltip', measureTooltip)
и удалять

Код: Выделить всё

Там где erase.getFeatures().on('change:length', ...
map.removeOverlay(e.feature.get('measureTooltip'))
Если я правильно понял.

Warden
Интересующийся
Сообщения: 25
Зарегистрирован: 16 сен 2015, 16:43
Репутация: 7
Откуда: Королёв

Re: OpenLayers3. Измерение дистанции и площади.

Сообщение Warden » 06 окт 2015, 08:58

MichaelK писал(а):Можно, например, overlay прямо в линию запихнуть

Код: Выделить всё

Там где lineDraw.on('drawend', function(evt){ ...
evt.feature.set('measureTooltip', measureTooltip)
и удалять

Код: Выделить всё

Там где erase.getFeatures().on('change:length', ...
map.removeOverlay(e.feature.get('measureTooltip'))
Если я правильно понял.
Ваш вариант имеет основание, но у меня выдает ексепшен, что невозможно получить property. А на работе сейчас не совсем хватает время разбираться в чем именно проблема. Благодарю за идею) :idea:

Ответить

Вернуться в «Веб-картография»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 0 гостей