/**
* Add a bemap.Polygon to the layer
* @public
* @param {bemap.Polygon} bemap.Polygon.
* @param {object} options
* @return {bemap.LeafletMap}
*/
bemap.LeafletMap.prototype.addPolygon = function(polygon, options) {
if (polygon && bemap.inheritsof(polygon, bemap.Polygon)) {
var style = polygon.getStyle();
if (!style) {
style = new bemap.PolygonStyle({
fillColor: new bemap.Color(0, 102, 204, 0.2),
borderColor: new bemap.Color(0, 102, 204, 1),
borderWidth: 2
});
}
var fillColor = style.getFillColor();
var borderColor = style.getBorderColor();
// Resolve the target layer FIRST so we can pass its path pane to
// L.polygon at construction (Leaflet honours `pane` only on init).
var opts = options || {};
var l = null;
if (opts.layer !== undefined && (bemap.inheritsof(opts.layer, bemap.VectorLayer))) {
l = opts.layer;
} else {
l = this.getLayerByName(bemap.Map.DEFAULT_LAYER.POLYGON);
if (l === null) {
l = new bemap.VectorLayer({
name: bemap.Map.DEFAULT_LAYER.POLYGON
});
this.addLayer(l);
}
}
var polygonOpts = {
fillColor: fillColor.getHex(),
fillOpacity: fillColor.getAlpha(),
color: borderColor.getHex(),
opacity: borderColor.getAlpha(),
weight: style.getBorderWidth()
};
if (l && l._paneNamePath) polygonOpts.pane = l._paneNamePath;
polygon.native = L.polygon(polygon.getLatLonArrays(), polygonOpts);
if (polygon.map === null) {
polygon.map = this;
}
if (polygon.layer === null) {
polygon.layer = l;
}
polygon.native.addTo(l.native);
}
return this;
};
/**
* Sync a polygon's MODEL coordinates FROM its native geometry.
*
* Direction matters, and this engine had it backwards (BEMAP-1898 audit).
* `bemap.Polygon.getCoordinates()` calls this and *then* returns `this.coords`,
* so the contract is a READ: native → model. That is what the OL engine does.
* Leaflet instead did `native.setLatLngs(polygon.getLatLonArrays())` — model →
* native — with two consequences:
* • any native-side change (a vertex edit, a drag) was silently OVERWRITTEN by
* the stale model on the next getCoordinates() call, and never reported;
* • inside draggablePolygon's mousemove the native was reset to the previous
* position, so the shape rendered one mousemove behind the cursor and landed
* one delta short. The handler compensated with a manual delta loop, which
* is removed now that this reads the right way round.
* @public
* @param {bemap.Polygon} polygon
* @return {bemap.LeafletMap} this
*/
bemap.LeafletMap.prototype.updatePolygonCoordinates = function(polygon) {
if (polygon && polygon.native && bemap.inheritsof(polygon, bemap.Polygon)) {
// L.Polygon nests rings; descend until the elements are LatLngs, so a simple
// polygon ([[LatLng,…]]) and a multi-ring one both resolve to the outer ring.
var ring = polygon.native.getLatLngs();
while (ring && ring.length && ring[0] && ring[0].lat === undefined) {
ring = ring[0];
}
if (!ring) return this;
for (var i = 0; i < ring.length; i++) {
var coord = polygon.coords[i];
if (coord && coord !== null && bemap.inheritsof(coord, bemap.Coordinate)) {
// Mutate in place, like OL: a consumer may hold a reference.
coord.setLon(ring[i].lng);
coord.setLat(ring[i].lat);
} else {
polygon.coords[i] = new bemap.Coordinate(ring[i].lng, ring[i].lat);
}
}
// Drop any model vertices the native no longer has (same as OL).
if (polygon.coords.length > ring.length) {
for (var j = polygon.coords.length; j > ring.length; j--) {
polygon.coords.pop();
}
}
}
return this;
};
bemap.LeafletMap.prototype.removePolygon = function(polygon) {
if (polygon && polygon.layer && polygon.layer.native && bemap.inheritsof(polygon, bemap.Polygon)) {
// Clean up vertex handles if editing was enabled
if (polygon._vertexHandlesLayer && polygon.map && polygon.map.native) {
polygon.map.native.removeLayer(polygon._vertexHandlesLayer);
polygon._vertexHandlesLayer = null;
}
polygon.map.native.removeLayer(polygon.native);
polygon.layer = null;
polygon.map = null;
}
return this;
};
/**
* Set the listner when an specified eventType occur on bemap.Polygon.
* @public
* @param {bemap.Polygon} polygon
* @param {bemap.Map.EventType} eventType Event type.
* @param {function} callback Function will be called when the specified eventType is occur.
* @param {object} options options.
* @return {bemap.Listener} this.
*/
bemap.LeafletMap.prototype.onPolygon = function(polygon, eventType, callback, options) {
var opts = options ? options : {};
var nativeListener = polygon.native.on(eventType, function(evt) {
var mapEvent = new bemap.MapEvent({
native: evt,
bemapObject: polygon,
x: evt.containerPoint ? evt.containerPoint.x : undefined,
y: evt.containerPoint ? evt.containerPoint.y : undefined,
coordinate: evt.latlng ? new bemap.Coordinate(evt.latlng.lng, evt.latlng.lat) : undefined,
properties: options,
map: this
});
callback(mapEvent);
});
var listener = new bemap.Listener({
native: nativeListener,
callback: callback,
key: eventType,
bemapObject: polygon
});
return listener;
};
/**
* Define the draggable capability for bemap.Polygon (Leaflet).
* @param {bemap.Polygon} polygon
* @param {function} callback
* @param {object} options
* @return {bemap.Listener}
*/
bemap.LeafletMap.prototype.draggablePolygon = function(polygon, callback, options) {
var _this = this;
polygon.native.on('mousedown', function(evt) {
L.DomEvent.stopPropagation(evt);
_this.native.dragging.disable();
var mouseStartLat = evt.latlng.lat;
var mouseStartLng = evt.latlng.lng;
var onMove = function(e) {
var dLat = e.latlng.lat - mouseStartLat;
var dLng = e.latlng.lng - mouseStartLng;
mouseStartLat = e.latlng.lat;
mouseStartLng = e.latlng.lng;
var rings = polygon.native.getLatLngs();
var newRings = [];
for (var r = 0; r < rings.length; r++) {
var ring = rings[r];
var newRing = [];
for (var i = 0; i < ring.length; i++) {
newRing.push(L.latLng(ring[i].lat + dLat, ring[i].lng + dLng));
}
newRings.push(newRing);
}
polygon.native.setLatLngs(newRings);
// The native has already moved; pull the model from it. This used to add
// the delta to the model BY HAND, which was only correct while
// updatePolygonCoordinates pushed model → native (and even then it left
// the shape a mousemove behind). Now that the sync reads native → model,
// keeping the manual loop would apply the delta twice.
_this.updatePolygonCoordinates(polygon);
};
_this.native.on('mousemove', onMove);
_this.native.once('mouseup', function(e) {
_this.native.off('mousemove', onMove);
_this.native.dragging.enable();
if (callback) {
callback(new bemap.MapEvent({
native: e, bemapObject: polygon,
coordinate: e.latlng ? new bemap.Coordinate(e.latlng.lng, e.latlng.lat) : undefined,
map: _this
}));
}
});
});
return new bemap.Listener({ native: polygon.native, bemapObject: polygon, key: 'dragFeature' });
};