src/pyams_gis/resources/js/Edit.Poly.js
changeset 0 c73bb834ccbe
equal deleted inserted replaced
-1:000000000000 0:c73bb834ccbe
       
     1 L.Edit = L.Edit || {};
       
     2 
       
     3 /**
       
     4  * @class L.Edit.Polyline
       
     5  * @aka L.Edit.Poly
       
     6  * @aka Edit.Poly
       
     7  */
       
     8 L.Edit.Poly = L.Handler.extend({
       
     9 	options: {},
       
    10 
       
    11 	// @method initialize(): void
       
    12 	initialize: function (poly, options) {
       
    13 
       
    14 		this.latlngs = [poly._latlngs];
       
    15 		if (poly._holes) {
       
    16 			this.latlngs = this.latlngs.concat(poly._holes);
       
    17 		}
       
    18 
       
    19 		this._poly = poly;
       
    20 		L.setOptions(this, options);
       
    21 
       
    22 		this._poly.on('revert-edited', this._updateLatLngs, this);
       
    23 	},
       
    24 
       
    25 	// Compatibility method to normalize Poly* objects
       
    26 	// between 0.7.x and 1.0+
       
    27 	_defaultShape: function () {
       
    28 		if (!L.Polyline._flat) {
       
    29 			return this._poly._latlngs;
       
    30 		}
       
    31 		return L.Polyline._flat(this._poly._latlngs) ? this._poly._latlngs : this._poly._latlngs[0];
       
    32 	},
       
    33 
       
    34 	_eachVertexHandler: function (callback) {
       
    35 		for (var i = 0; i < this._verticesHandlers.length; i++) {
       
    36 			callback(this._verticesHandlers[i]);
       
    37 		}
       
    38 	},
       
    39 
       
    40 	// @method addHooks(): void
       
    41 	// Add listener hooks to this handler
       
    42 	addHooks: function () {
       
    43 		this._initHandlers();
       
    44 		this._eachVertexHandler(function (handler) {
       
    45 			handler.addHooks();
       
    46 		});
       
    47 	},
       
    48 
       
    49 	// @method removeHooks(): void
       
    50 	// Remove listener hooks from this handler
       
    51 	removeHooks: function () {
       
    52 		this._eachVertexHandler(function (handler) {
       
    53 			handler.removeHooks();
       
    54 		});
       
    55 	},
       
    56 
       
    57 	// @method updateMarkers(): void
       
    58 	// Fire an update for each vertex handler
       
    59 	updateMarkers: function () {
       
    60 		this._eachVertexHandler(function (handler) {
       
    61 			handler.updateMarkers();
       
    62 		});
       
    63 	},
       
    64 
       
    65 	_initHandlers: function () {
       
    66 		this._verticesHandlers = [];
       
    67 		for (var i = 0; i < this.latlngs.length; i++) {
       
    68 			this._verticesHandlers.push(new L.Edit.PolyVerticesEdit(this._poly, this.latlngs[i], this.options));
       
    69 		}
       
    70 	},
       
    71 
       
    72 	_updateLatLngs: function (e) {
       
    73 		this.latlngs = [e.layer._latlngs];
       
    74 		if (e.layer._holes) {
       
    75 			this.latlngs = this.latlngs.concat(e.layer._holes);
       
    76 		}
       
    77 	}
       
    78 
       
    79 });
       
    80 
       
    81 /**
       
    82  * @class L.Edit.PolyVerticesEdit
       
    83  * @aka Edit.PolyVerticesEdit
       
    84  */
       
    85 L.Edit.PolyVerticesEdit = L.Handler.extend({
       
    86 	options: {
       
    87 		icon: new L.DivIcon({
       
    88 			iconSize: new L.Point(8, 8),
       
    89 			className: 'leaflet-div-icon leaflet-editing-icon'
       
    90 		}),
       
    91 		touchIcon: new L.DivIcon({
       
    92 			iconSize: new L.Point(20, 20),
       
    93 			className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'
       
    94 		}),
       
    95 		drawError: {
       
    96 			color: '#b00b00',
       
    97 			timeout: 1000
       
    98 		}
       
    99 
       
   100 
       
   101 	},
       
   102 
       
   103 	// @method intialize(): void
       
   104 	initialize: function (poly, latlngs, options) {
       
   105 		// if touch, switch to touch icon
       
   106 		if (L.Browser.touch) {
       
   107 			this.options.icon = this.options.touchIcon;
       
   108 		}
       
   109 		this._poly = poly;
       
   110 
       
   111 		if (options && options.drawError) {
       
   112 			options.drawError = L.Util.extend({}, this.options.drawError, options.drawError);
       
   113 		}
       
   114 
       
   115 		this._latlngs = latlngs;
       
   116 
       
   117 		L.setOptions(this, options);
       
   118 	},
       
   119 
       
   120 	// Compatibility method to normalize Poly* objects
       
   121 	// between 0.7.x and 1.0+
       
   122 	_defaultShape: function () {
       
   123 		if (!L.Polyline._flat) {
       
   124 			return this._latlngs;
       
   125 		}
       
   126 		return L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];
       
   127 	},
       
   128 
       
   129 	// @method addHooks(): void
       
   130 	// Add listener hooks to this handler.
       
   131 	addHooks: function () {
       
   132 		var poly = this._poly;
       
   133 
       
   134 		if (!(poly instanceof L.Polygon)) {
       
   135 			poly.options.fill = false;
       
   136 			if (poly.options.editing) {
       
   137 				poly.options.editing.fill = false;
       
   138 			}
       
   139 		}
       
   140 
       
   141 		poly.setStyle(poly.options.editing);
       
   142 
       
   143 		if (this._poly._map) {
       
   144 
       
   145 			this._map = this._poly._map; // Set map
       
   146 
       
   147 			if (!this._markerGroup) {
       
   148 				this._initMarkers();
       
   149 			}
       
   150 			this._poly._map.addLayer(this._markerGroup);
       
   151 		}
       
   152 	},
       
   153 
       
   154 	// @method removeHooks(): void
       
   155 	// Remove listener hooks from this handler.
       
   156 	removeHooks: function () {
       
   157 		var poly = this._poly;
       
   158 
       
   159 		poly.setStyle(poly.options.original);
       
   160 
       
   161 		if (poly._map) {
       
   162 			poly._map.removeLayer(this._markerGroup);
       
   163 			delete this._markerGroup;
       
   164 			delete this._markers;
       
   165 		}
       
   166 	},
       
   167 
       
   168 	// @method updateMarkers(): void
       
   169 	// Clear markers and update their location
       
   170 	updateMarkers: function () {
       
   171 		this._markerGroup.clearLayers();
       
   172 		this._initMarkers();
       
   173 	},
       
   174 
       
   175 	_initMarkers: function () {
       
   176 		if (!this._markerGroup) {
       
   177 			this._markerGroup = new L.LayerGroup();
       
   178 		}
       
   179 		this._markers = [];
       
   180 
       
   181 		var latlngs = this._defaultShape(),
       
   182 			i, j, len, marker;
       
   183 
       
   184 		for (i = 0, len = latlngs.length; i < len; i++) {
       
   185 
       
   186 			marker = this._createMarker(latlngs[i], i);
       
   187 			marker.on('click', this._onMarkerClick, this);
       
   188 			this._markers.push(marker);
       
   189 		}
       
   190 
       
   191 		var markerLeft, markerRight;
       
   192 
       
   193 		for (i = 0, j = len - 1; i < len; j = i++) {
       
   194 			if (i === 0 && !(L.Polygon && (this._poly instanceof L.Polygon))) {
       
   195 				continue;
       
   196 			}
       
   197 
       
   198 			markerLeft = this._markers[j];
       
   199 			markerRight = this._markers[i];
       
   200 
       
   201 			this._createMiddleMarker(markerLeft, markerRight);
       
   202 			this._updatePrevNext(markerLeft, markerRight);
       
   203 		}
       
   204 	},
       
   205 
       
   206 	_createMarker: function (latlng, index) {
       
   207 		// Extending L.Marker in TouchEvents.js to include touch.
       
   208 		var marker = new L.Marker.Touch(latlng, {
       
   209 			draggable: true,
       
   210 			icon: this.options.icon,
       
   211 		});
       
   212 
       
   213 		marker._origLatLng = latlng;
       
   214 		marker._index = index;
       
   215 
       
   216 		marker
       
   217 			.on('dragstart', this._onMarkerDragStart, this)
       
   218 			.on('drag', this._onMarkerDrag, this)
       
   219 			.on('dragend', this._fireEdit, this)
       
   220 			.on('touchmove', this._onTouchMove, this)
       
   221 			.on('touchend', this._fireEdit, this)
       
   222 			.on('MSPointerMove', this._onTouchMove, this)
       
   223 			.on('MSPointerUp', this._fireEdit, this);
       
   224 
       
   225 		this._markerGroup.addLayer(marker);
       
   226 
       
   227 		return marker;
       
   228 	},
       
   229 
       
   230 	_onMarkerDragStart: function () {
       
   231 		this._poly.fire('editstart');
       
   232 	},
       
   233 
       
   234 	_spliceLatLngs: function () {
       
   235 		var latlngs = this._defaultShape();
       
   236 		var removed = [].splice.apply(latlngs, arguments);
       
   237 		this._poly._convertLatLngs(latlngs, true);
       
   238 		this._poly.redraw();
       
   239 		return removed;
       
   240 	},
       
   241 
       
   242 	_removeMarker: function (marker) {
       
   243 		var i = marker._index;
       
   244 
       
   245 		this._markerGroup.removeLayer(marker);
       
   246 		this._markers.splice(i, 1);
       
   247 		this._spliceLatLngs(i, 1);
       
   248 		this._updateIndexes(i, -1);
       
   249 
       
   250 		marker
       
   251 			.off('dragstart', this._onMarkerDragStart, this)
       
   252 			.off('drag', this._onMarkerDrag, this)
       
   253 			.off('dragend', this._fireEdit, this)
       
   254 			.off('touchmove', this._onMarkerDrag, this)
       
   255 			.off('touchend', this._fireEdit, this)
       
   256 			.off('click', this._onMarkerClick, this)
       
   257 			.off('MSPointerMove', this._onTouchMove, this)
       
   258 			.off('MSPointerUp', this._fireEdit, this);
       
   259 	},
       
   260 
       
   261 	_fireEdit: function () {
       
   262 		this._poly.edited = true;
       
   263 		this._poly.fire('edit');
       
   264 		this._poly._map.fire(L.Draw.Event.EDITVERTEX, { layers: this._markerGroup, poly: this._poly });
       
   265 	},
       
   266 
       
   267 	_onMarkerDrag: function (e) {
       
   268 		var marker = e.target;
       
   269 		var poly = this._poly;
       
   270 
       
   271 		L.extend(marker._origLatLng, marker._latlng);
       
   272 
       
   273 		if (marker._middleLeft) {
       
   274 			marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
       
   275 		}
       
   276 		if (marker._middleRight) {
       
   277 			marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
       
   278 		}
       
   279 
       
   280 		if (poly.options.poly) {
       
   281 			var tooltip = poly._map._editTooltip; // Access the tooltip
       
   282 
       
   283 			// If we don't allow intersections and the polygon intersects
       
   284 			if (!poly.options.poly.allowIntersection && poly.intersects()) {
       
   285 
       
   286 				var originalColor = poly.options.color;
       
   287 				poly.setStyle({ color: this.options.drawError.color });
       
   288 
       
   289 				// Manually trigger 'dragend' behavior on marker we are about to remove
       
   290 				// WORKAROUND: introduced in 1.0.0-rc2, may be related to #4484
       
   291 				if (L.version.indexOf('0.7') !== 0) {
       
   292 					marker.dragging._draggable._onUp(e);
       
   293 				}
       
   294 				this._onMarkerClick(e); // Remove violating marker
       
   295 				// FIXME: Reset the marker to it's original position (instead of remove)
       
   296 
       
   297 				if (tooltip) {
       
   298 					tooltip.updateContent({
       
   299 						text: L.drawLocal.draw.handlers.polyline.error
       
   300 					});
       
   301 				}
       
   302 
       
   303 				// Reset everything back to normal after a second
       
   304 				setTimeout(function () {
       
   305 					poly.setStyle({ color: originalColor });
       
   306 					if (tooltip) {
       
   307 						tooltip.updateContent({
       
   308 							text: L.drawLocal.edit.handlers.edit.tooltip.text,
       
   309 							subtext: L.drawLocal.edit.handlers.edit.tooltip.subtext
       
   310 						});
       
   311 					}
       
   312 				}, 1000);
       
   313 			}
       
   314 		}
       
   315 
       
   316 		this._poly.redraw();
       
   317 		this._poly.fire('editdrag');
       
   318 	},
       
   319 
       
   320 	_onMarkerClick: function (e) {
       
   321 
       
   322 		var minPoints = L.Polygon && (this._poly instanceof L.Polygon) ? 4 : 3,
       
   323 			marker = e.target;
       
   324 
       
   325 		// If removing this point would create an invalid polyline/polygon don't remove
       
   326 		if (this._defaultShape().length < minPoints) {
       
   327 			return;
       
   328 		}
       
   329 
       
   330 		// remove the marker
       
   331 		this._removeMarker(marker);
       
   332 
       
   333 		// update prev/next links of adjacent markers
       
   334 		this._updatePrevNext(marker._prev, marker._next);
       
   335 
       
   336 		// remove ghost markers near the removed marker
       
   337 		if (marker._middleLeft) {
       
   338 			this._markerGroup.removeLayer(marker._middleLeft);
       
   339 		}
       
   340 		if (marker._middleRight) {
       
   341 			this._markerGroup.removeLayer(marker._middleRight);
       
   342 		}
       
   343 
       
   344 		// create a ghost marker in place of the removed one
       
   345 		if (marker._prev && marker._next) {
       
   346 			this._createMiddleMarker(marker._prev, marker._next);
       
   347 
       
   348 		} else if (!marker._prev) {
       
   349 			marker._next._middleLeft = null;
       
   350 
       
   351 		} else if (!marker._next) {
       
   352 			marker._prev._middleRight = null;
       
   353 		}
       
   354 
       
   355 		this._fireEdit();
       
   356 	},
       
   357 
       
   358 	_onTouchMove: function (e) {
       
   359 
       
   360 		var layerPoint = this._map.mouseEventToLayerPoint(e.originalEvent.touches[0]),
       
   361 			latlng = this._map.layerPointToLatLng(layerPoint),
       
   362 			marker = e.target;
       
   363 
       
   364 		L.extend(marker._origLatLng, latlng);
       
   365 
       
   366 		if (marker._middleLeft) {
       
   367 			marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
       
   368 		}
       
   369 		if (marker._middleRight) {
       
   370 			marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
       
   371 		}
       
   372 
       
   373 		this._poly.redraw();
       
   374 		this.updateMarkers();
       
   375 	},
       
   376 
       
   377 	_updateIndexes: function (index, delta) {
       
   378 		this._markerGroup.eachLayer(function (marker) {
       
   379 			if (marker._index > index) {
       
   380 				marker._index += delta;
       
   381 			}
       
   382 		});
       
   383 	},
       
   384 
       
   385 	_createMiddleMarker: function (marker1, marker2) {
       
   386 		var latlng = this._getMiddleLatLng(marker1, marker2),
       
   387 			marker = this._createMarker(latlng),
       
   388 			onClick,
       
   389 			onDragStart,
       
   390 			onDragEnd;
       
   391 
       
   392 		marker.setOpacity(0.6);
       
   393 
       
   394 		marker1._middleRight = marker2._middleLeft = marker;
       
   395 
       
   396 		onDragStart = function () {
       
   397 			marker.off('touchmove', onDragStart, this);
       
   398 			var i = marker2._index;
       
   399 
       
   400 			marker._index = i;
       
   401 
       
   402 			marker
       
   403 				.off('click', onClick, this)
       
   404 				.on('click', this._onMarkerClick, this);
       
   405 
       
   406 			latlng.lat = marker.getLatLng().lat;
       
   407 			latlng.lng = marker.getLatLng().lng;
       
   408 			this._spliceLatLngs(i, 0, latlng);
       
   409 			this._markers.splice(i, 0, marker);
       
   410 
       
   411 			marker.setOpacity(1);
       
   412 
       
   413 			this._updateIndexes(i, 1);
       
   414 			marker2._index++;
       
   415 			this._updatePrevNext(marker1, marker);
       
   416 			this._updatePrevNext(marker, marker2);
       
   417 
       
   418 			this._poly.fire('editstart');
       
   419 		};
       
   420 
       
   421 		onDragEnd = function () {
       
   422 			marker.off('dragstart', onDragStart, this);
       
   423 			marker.off('dragend', onDragEnd, this);
       
   424 			marker.off('touchmove', onDragStart, this);
       
   425 
       
   426 			this._createMiddleMarker(marker1, marker);
       
   427 			this._createMiddleMarker(marker, marker2);
       
   428 		};
       
   429 
       
   430 		onClick = function () {
       
   431 			onDragStart.call(this);
       
   432 			onDragEnd.call(this);
       
   433 			this._fireEdit();
       
   434 		};
       
   435 
       
   436 		marker
       
   437 			.on('click', onClick, this)
       
   438 			.on('dragstart', onDragStart, this)
       
   439 			.on('dragend', onDragEnd, this)
       
   440 			.on('touchmove', onDragStart, this);
       
   441 
       
   442 		this._markerGroup.addLayer(marker);
       
   443 	},
       
   444 
       
   445 	_updatePrevNext: function (marker1, marker2) {
       
   446 		if (marker1) {
       
   447 			marker1._next = marker2;
       
   448 		}
       
   449 		if (marker2) {
       
   450 			marker2._prev = marker1;
       
   451 		}
       
   452 	},
       
   453 
       
   454 	_getMiddleLatLng: function (marker1, marker2) {
       
   455 		var map = this._poly._map,
       
   456 			p1 = map.project(marker1.getLatLng()),
       
   457 			p2 = map.project(marker2.getLatLng());
       
   458 
       
   459 		return map.unproject(p1._add(p2)._divideBy(2));
       
   460 	}
       
   461 });
       
   462 
       
   463 L.Polyline.addInitHook(function () {
       
   464 
       
   465 	// Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.Handler.PolyEdit
       
   466 	if (this.editing) {
       
   467 		return;
       
   468 	}
       
   469 
       
   470 	if (L.Edit.Poly) {
       
   471 
       
   472 		this.editing = new L.Edit.Poly(this, this.options.poly);
       
   473 
       
   474 		if (this.options.editable) {
       
   475 			this.editing.enable();
       
   476 		}
       
   477 	}
       
   478 
       
   479 	this.on('add', function () {
       
   480 		if (this.editing && this.editing.enabled()) {
       
   481 			this.editing.addHooks();
       
   482 		}
       
   483 	});
       
   484 
       
   485 	this.on('remove', function () {
       
   486 		if (this.editing && this.editing.enabled()) {
       
   487 			this.editing.removeHooks();
       
   488 		}
       
   489 	});
       
   490 });