Installed leaflet in extlib

This commit is contained in:
Joar Wandborg
2012-01-10 01:54:37 +01:00
parent c47a03b909
commit c5ba5b0456
96 changed files with 5756 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
/*
* L.FeatureGroup extends L.LayerGroup by introducing mouse events and bindPopup method shared between a group of layers.
*/
L.FeatureGroup = L.LayerGroup.extend({
includes: L.Mixin.Events,
addLayer: function(layer) {
this._initEvents(layer);
L.LayerGroup.prototype.addLayer.call(this, layer);
if (this._popupContent && layer.bindPopup) {
layer.bindPopup(this._popupContent);
}
},
bindPopup: function(content) {
this._popupContent = content;
for (var i in this._layers) {
if (this._layers.hasOwnProperty(i) && this._layers[i].bindPopup) {
this._layers[i].bindPopup(content);
}
}
},
_events: ['click', 'dblclick', 'mouseover', 'mouseout'],
_initEvents: function(layer) {
for (var i = 0, len = this._events.length; i < len; i++) {
layer.on(this._events[i], this._propagateEvent, this);
}
},
_propagateEvent: function(e) {
e.layer = e.target;
e.target = this;
this.fire(e.type, e);
}
});

View File

@@ -0,0 +1,106 @@
L.GeoJSON = L.LayerGroup.extend({
includes: L.Mixin.Events,
initialize: function(geojson, options) {
L.Util.setOptions(this, options);
this._geojson = geojson;
this._layers = {};
if (geojson) {
this.addGeoJSON(geojson);
}
},
addGeoJSON: function(geojson) {
if (geojson.features) {
for (var i = 0, len = geojson.features.length; i < len; i++) {
this.addGeoJSON(geojson.features[i]);
}
return;
}
var isFeature = (geojson.type == 'Feature'),
geometry = (isFeature ? geojson.geometry : geojson),
layer = L.GeoJSON.geometryToLayer(geometry, this.options.pointToLayer);
this.fire('featureparse', {
layer: layer,
properties: geojson.properties,
geometryType: geometry.type,
bbox: geojson.bbox,
id: geojson.id
});
this.addLayer(layer);
}
});
L.Util.extend(L.GeoJSON, {
geometryToLayer: function(geometry, pointToLayer) {
var coords = geometry.coordinates,
latlng, latlngs,
i, len,
layer,
layers = [];
switch (geometry.type) {
case 'Point':
latlng = this.coordsToLatLng(coords);
return pointToLayer ? pointToLayer(latlng) : new L.Marker(latlng);
case 'MultiPoint':
for (i = 0, len = coords.length; i < len; i++) {
latlng = this.coordsToLatLng(coords[i]);
layer = pointToLayer ? pointToLayer(latlng) : new L.Marker(latlng);
layers.push(layer);
}
return new L.FeatureGroup(layers);
case 'LineString':
latlngs = this.coordsToLatLngs(coords);
return new L.Polyline(latlngs);
case 'Polygon':
latlngs = this.coordsToLatLngs(coords, 1);
return new L.Polygon(latlngs);
case 'MultiLineString':
latlngs = this.coordsToLatLngs(coords, 1);
return new L.MultiPolyline(latlngs);
case "MultiPolygon":
latlngs = this.coordsToLatLngs(coords, 2);
return new L.MultiPolygon(latlngs);
case "GeometryCollection":
for (i = 0, len = geometry.geometries.length; i < len; i++) {
layer = this.geometryToLayer(geometry.geometries[i]);
layers.push(layer);
}
return new L.FeatureGroup(layers);
default:
throw new Error('Invalid GeoJSON object.');
}
},
coordsToLatLng: function(/*Array*/ coords, /*Boolean*/ reverse)/*: LatLng*/ {
var lat = parseFloat(coords[reverse ? 0 : 1]),
lng = parseFloat(coords[reverse ? 1 : 0]);
return new L.LatLng(lat, lng);
},
coordsToLatLngs: function(/*Array*/ coords, /*Number*/ levelsDeep, /*Boolean*/ reverse)/*: Array*/ {
var latlng, latlngs = [],
i, len = coords.length;
for (i = 0; i < len; i++) {
latlng = levelsDeep ?
this.coordsToLatLngs(coords[i], levelsDeep - 1, reverse) :
this.coordsToLatLng(coords[i], reverse);
latlngs.push(latlng);
}
return latlngs;
}
});

View File

@@ -0,0 +1,58 @@
L.ImageOverlay = L.Class.extend({
includes: L.Mixin.Events,
initialize: function(/*String*/ url, /*LatLngBounds*/ bounds) {
this._url = url;
this._bounds = bounds;
},
onAdd: function(map) {
this._map = map;
if (!this._image) {
this._initImage();
}
map.getPanes().overlayPane.appendChild(this._image);
map.on('viewreset', this._reset, this);
this._reset();
},
onRemove: function(map) {
map.getPanes().overlayPane.removeChild(this._image);
map.off('viewreset', this._reset, this);
},
_initImage: function() {
this._image = L.DomUtil.create('img', 'leaflet-image-layer');
this._image.style.visibility = 'hidden';
//TODO opacity option
//TODO createImage util method to remove duplication
L.Util.extend(this._image, {
galleryimg: 'no',
onselectstart: L.Util.falseFn,
onmousemove: L.Util.falseFn,
onload: this._onImageLoad,
src: this._url
});
},
_reset: function() {
var topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
bottomRight = this._map.latLngToLayerPoint(this._bounds.getSouthEast()),
size = bottomRight.subtract(topLeft);
L.DomUtil.setPosition(this._image, topLeft);
this._image.style.width = size.x + 'px';
this._image.style.height = size.y + 'px';
},
_onImageLoad: function() {
this.style.visibility = '';
//TODO fire layerload
}
});

View File

@@ -0,0 +1,58 @@
/*
* L.LayerGroup is a class to combine several layers so you can manipulate the group (e.g. add/remove it) as one layer.
*/
L.LayerGroup = L.Class.extend({
initialize: function(layers) {
this._layers = {};
if (layers) {
for (var i = 0, len = layers.length; i < len; i++) {
this.addLayer(layers[i]);
}
}
},
addLayer: function(layer) {
var id = L.Util.stamp(layer);
this._layers[id] = layer;
if (this._map) {
this._map.addLayer(layer);
}
return this;
},
removeLayer: function(layer) {
var id = L.Util.stamp(layer);
delete this._layers[id];
if (this._map) {
this._map.removeLayer(layer);
}
return this;
},
clearLayers: function() {
this._iterateLayers(this.removeLayer, this);
return this;
},
onAdd: function(map) {
this._map = map;
this._iterateLayers(map.addLayer, map);
},
onRemove: function(map) {
this._iterateLayers(map.removeLayer, map);
delete this._map;
},
_iterateLayers: function(method, context) {
for (var i in this._layers) {
if (this._layers.hasOwnProperty(i)) {
method.call(context, this._layers[i]);
}
}
}
});

View File

@@ -0,0 +1,165 @@
L.Popup = L.Class.extend({
includes: L.Mixin.Events,
options: {
maxWidth: 300,
autoPan: true,
closeButton: true,
offset: new L.Point(0, 2),
autoPanPadding: new L.Point(5, 5)
},
initialize: function(options) {
L.Util.setOptions(this, options);
},
onAdd: function(map) {
this._map = map;
if (!this._container) {
this._initLayout();
}
this._updateContent();
this._container.style.opacity = '0';
this._map._panes.popupPane.appendChild(this._container);
this._map.on('viewreset', this._updatePosition, this);
if (this._map.options.closePopupOnClick) {
this._map.on('preclick', this._close, this);
}
this._update();
this._container.style.opacity = '1'; //TODO fix ugly opacity hack
this._opened = true;
},
onRemove: function(map) {
map._panes.popupPane.removeChild(this._container);
map.off('viewreset', this._updatePosition, this);
map.off('click', this._close, this);
this._container.style.opacity = '0';
this._opened = false;
},
setLatLng: function(latlng) {
this._latlng = latlng;
if (this._opened) {
this._update();
}
return this;
},
setContent: function(content) {
this._content = content;
if (this._opened) {
this._update();
}
return this;
},
_close: function() {
if (this._opened) {
this._map.removeLayer(this);
}
},
_initLayout: function() {
this._container = L.DomUtil.create('div', 'leaflet-popup');
this._closeButton = L.DomUtil.create('a', 'leaflet-popup-close-button', this._container);
this._closeButton.href = '#close';
this._closeButton.onclick = L.Util.bind(this._onCloseButtonClick, this);
this._wrapper = L.DomUtil.create('div', 'leaflet-popup-content-wrapper', this._container);
L.DomEvent.disableClickPropagation(this._wrapper);
this._contentNode = L.DomUtil.create('div', 'leaflet-popup-content', this._wrapper);
this._tipContainer = L.DomUtil.create('div', 'leaflet-popup-tip-container', this._container);
this._tip = L.DomUtil.create('div', 'leaflet-popup-tip', this._tipContainer);
},
_update: function() {
this._container.style.visibility = 'hidden';
this._updateContent();
this._updateLayout();
this._updatePosition();
this._container.style.visibility = '';
this._adjustPan();
},
_updateContent: function() {
if (!this._content) return;
if (typeof this._content == 'string') {
this._contentNode.innerHTML = this._content;
} else {
this._contentNode.innerHTML = '';
this._contentNode.appendChild(this._content);
}
},
_updateLayout: function() {
this._container.style.width = '';
this._container.style.whiteSpace = 'nowrap';
var width = this._container.offsetWidth;
this._container.style.width = (width > this.options.maxWidth ? this.options.maxWidth : width) + 'px';
this._container.style.whiteSpace = '';
this._containerWidth = this._container.offsetWidth;
},
_updatePosition: function() {
var pos = this._map.latLngToLayerPoint(this._latlng);
this._containerBottom = -pos.y - this.options.offset.y;
this._containerLeft = pos.x - Math.round(this._containerWidth/2) + this.options.offset.x;
this._container.style.bottom = this._containerBottom + 'px';
this._container.style.left = this._containerLeft + 'px';
},
_adjustPan: function() {
if (!this.options.autoPan) { return; }
var containerHeight = this._container.offsetHeight,
layerPos = new L.Point(
this._containerLeft,
-containerHeight - this._containerBottom),
containerPos = this._map.layerPointToContainerPoint(layerPos),
adjustOffset = new L.Point(0, 0),
padding = this.options.autoPanPadding,
size = this._map.getSize();
if (containerPos.x < 0) {
adjustOffset.x = containerPos.x - padding.x;
}
if (containerPos.x + this._containerWidth > size.x) {
adjustOffset.x = containerPos.x + this._containerWidth - size.x + padding.x;
}
if (containerPos.y < 0) {
adjustOffset.y = containerPos.y - padding.y;
}
if (containerPos.y + containerHeight > size.y) {
adjustOffset.y = containerPos.y + containerHeight - size.y + padding.y;
}
if (adjustOffset.x || adjustOffset.y) {
this._map.panBy(adjustOffset);
}
},
_onCloseButtonClick: function(e) {
this._close();
L.DomEvent.stop(e);
}
});

View File

@@ -0,0 +1,56 @@
L.Icon = L.Class.extend({
iconUrl: L.ROOT_URL + 'images/marker.png',
shadowUrl: L.ROOT_URL + 'images/marker-shadow.png',
iconSize: new L.Point(25, 41),
shadowSize: new L.Point(41, 41),
iconAnchor: new L.Point(13, 41),
popupAnchor: new L.Point(0, -33),
initialize: function(iconUrl) {
if (iconUrl) {
this.iconUrl = iconUrl;
}
},
createIcon: function() {
return this._createIcon('icon');
},
createShadow: function() {
return this._createIcon('shadow');
},
_createIcon: function(name) {
var size = this[name + 'Size'],
src = this[name + 'Url'],
img = this._createImg(src);
if (!src) { return null; }
img.className = 'leaflet-marker-' + name;
img.style.marginLeft = (-this.iconAnchor.x) + 'px';
img.style.marginTop = (-this.iconAnchor.y) + 'px';
if (size) {
img.style.width = size.x + 'px';
img.style.height = size.y + 'px';
}
return img;
},
_createImg: function(src) {
var el;
if (!L.Browser.ie6) {
el = document.createElement('img');
el.src = src;
} else {
el = document.createElement('div');
el.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + src + '")';
}
return el;
}
});

View File

@@ -0,0 +1,28 @@
/*
* Popup extension to L.Marker, adding openPopup & bindPopup methods.
*/
L.Marker.include({
openPopup: function() {
this._popup.setLatLng(this._latlng);
this._map.openPopup(this._popup);
return this;
},
closePopup: function() {
if (this._popup) {
this._popup._close();
}
},
bindPopup: function(content, options) {
options = L.Util.extend({offset: this.options.icon.popupAnchor}, options);
this._popup = new L.Popup(options);
this._popup.setContent(content);
this.on('click', this.openPopup, this);
return this;
}
});

View File

@@ -0,0 +1,123 @@
/*
* L.Marker is used to display clickable/draggable icons on the map.
*/
L.Marker = L.Class.extend({
includes: L.Mixin.Events,
options: {
icon: new L.Icon(),
title: '',
clickable: true,
draggable: false
},
initialize: function(latlng, options) {
L.Util.setOptions(this, options);
this._latlng = latlng;
},
onAdd: function(map) {
this._map = map;
this._initIcon();
map.on('viewreset', this._reset, this);
this._reset();
},
onRemove: function(map) {
this._removeIcon();
map.off('viewreset', this._reset, this);
},
getLatLng: function() {
return this._latlng;
},
setLatLng: function(latlng) {
this._latlng = latlng;
this._reset();
},
setIcon: function(icon) {
this._removeIcon();
this._icon = this._shadow = null;
this.options.icon = icon;
this._initIcon();
},
_initIcon: function() {
if (!this._icon) {
this._icon = this.options.icon.createIcon();
if (this.options.title) {
this._icon.title = this.options.title;
}
this._initInteraction();
}
if (!this._shadow) {
this._shadow = this.options.icon.createShadow();
}
this._map._panes.markerPane.appendChild(this._icon);
if (this._shadow) {
this._map._panes.shadowPane.appendChild(this._shadow);
}
},
_removeIcon: function() {
this._map._panes.markerPane.removeChild(this._icon);
if (this._shadow) {
this._map._panes.shadowPane.removeChild(this._shadow);
}
},
_reset: function() {
var pos = this._map.latLngToLayerPoint(this._latlng).round();
L.DomUtil.setPosition(this._icon, pos);
if (this._shadow) {
L.DomUtil.setPosition(this._shadow, pos);
}
this._icon.style.zIndex = pos.y;
},
_initInteraction: function() {
if (this.options.clickable) {
this._icon.className += ' leaflet-clickable';
L.DomEvent.addListener(this._icon, 'click', this._onMouseClick, this);
var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];
for (var i = 0; i < events.length; i++) {
L.DomEvent.addListener(this._icon, events[i], this._fireMouseEvent, this);
}
}
if (L.Handler.MarkerDrag) {
this.dragging = new L.Handler.MarkerDrag(this);
if (this.options.draggable) {
this.dragging.enable();
}
}
},
_onMouseClick: function(e) {
L.DomEvent.stopPropagation(e);
if (this.dragging && this.dragging.moved()) { return; }
this.fire(e.type);
},
_fireMouseEvent: function(e) {
this.fire(e.type);
L.DomEvent.stopPropagation(e);
}
});

View File

@@ -0,0 +1,41 @@
L.TileLayer.Canvas = L.TileLayer.extend({
options: {
async: false
},
initialize: function(options) {
L.Util.setOptions(this, options);
},
_createTileProto: function() {
this._canvasProto = L.DomUtil.create('canvas', 'leaflet-tile');
var tileSize = this.options.tileSize;
this._canvasProto.width = tileSize;
this._canvasProto.height = tileSize;
},
_createTile: function() {
var tile = this._canvasProto.cloneNode(false);
tile.onselectstart = tile.onmousemove = L.Util.falseFn;
return tile;
},
_loadTile: function(tile, tilePoint, zoom) {
tile._layer = this;
this.drawTile(tile, tilePoint, zoom);
if (!this.options.async) {
this.tileDrawn(tile);
}
},
drawTile: function(tile, tilePoint, zoom) {
// override with rendering code
},
tileDrawn: function(tile) {
this._tileOnLoad.call(tile);
}
});

View File

@@ -0,0 +1,47 @@
L.TileLayer.WMS = L.TileLayer.extend({
defaultWmsParams: {
service: 'WMS',
request: 'GetMap',
version: '1.1.1',
layers: '',
styles: '',
format: 'image/jpeg',
transparent: false
},
initialize: function(/*String*/ url, /*Object*/ options) {
this._url = url;
this.wmsParams = L.Util.extend({}, this.defaultWmsParams);
this.wmsParams.width = this.wmsParams.height = this.options.tileSize;
for (var i in options) {
// all keys that are not TileLayer options go to WMS params
if (!this.options.hasOwnProperty(i)) {
this.wmsParams[i] = options[i];
}
}
L.Util.setOptions(this, options);
},
onAdd: function(map) {
var projectionKey = (parseFloat(this.wmsParams.version) >= 1.3 ? 'crs' : 'srs');
this.wmsParams[projectionKey] = map.options.crs.code;
L.TileLayer.prototype.onAdd.call(this, map);
},
getTileUrl: function(/*Point*/ tilePoint, /*Number*/ zoom)/*-> String*/ {
var tileSize = this.options.tileSize,
nwPoint = tilePoint.multiplyBy(tileSize),
sePoint = nwPoint.add(new L.Point(tileSize, tileSize)),
nwMap = this._map.unproject(nwPoint, this._zoom, true),
seMap = this._map.unproject(sePoint, this._zoom, true),
nw = this._map.options.crs.project(nwMap),
se = this._map.options.crs.project(seMap),
bbox = [nw.x, se.y, se.x, nw.y].join(',');
return this._url + L.Util.getParamString(this.wmsParams) + "&bbox=" + bbox;
}
});

View File

@@ -0,0 +1,262 @@
/*
* L.TileLayer is used for standard xyz-numbered tile layers.
*/
L.TileLayer = L.Class.extend({
includes: L.Mixin.Events,
options: {
minZoom: 0,
maxZoom: 18,
tileSize: 256,
subdomains: 'abc',
errorTileUrl: '',
attribution: '',
opacity: 1,
scheme: 'xyz',
noWrap: false,
unloadInvisibleTiles: L.Browser.mobileWebkit,
updateWhenIdle: L.Browser.mobileWebkit
},
initialize: function(url, options) {
L.Util.setOptions(this, options);
this._url = url;
if (typeof this.options.subdomains == 'string') {
this.options.subdomains = this.options.subdomains.split('');
}
},
onAdd: function(map) {
this._map = map;
// create a container div for tiles
this._initContainer();
// create an image to clone for tiles
this._createTileProto();
// set up events
map.on('viewreset', this._reset, this);
if (this.options.updateWhenIdle) {
map.on('moveend', this._update, this);
} else {
this._limitedUpdate = L.Util.limitExecByInterval(this._update, 100, this);
map.on('move', this._limitedUpdate, this);
}
this._reset();
this._update();
},
onRemove: function(map) {
this._map.getPanes().tilePane.removeChild(this._container);
this._container = null;
this._map.off('viewreset', this._reset, this);
if (this.options.updateWhenIdle) {
this._map.off('moveend', this._update, this);
} else {
this._map.off('move', this._limitedUpdate, this);
}
},
getAttribution: function() {
return this.options.attribution;
},
setOpacity: function(opacity) {
this.options.opacity = opacity;
this._setOpacity(opacity);
// stupid webkit hack to force redrawing of tiles
if (L.Browser.webkit) {
for (i in this._tiles) {
this._tiles[i].style.webkitTransform += ' translate(0,0)';
}
}
},
_setOpacity: function(opacity) {
if (opacity < 1) {
L.DomUtil.setOpacity(this._container, opacity);
}
},
_initContainer: function() {
var tilePane = this._map.getPanes().tilePane;
if (!this._container || tilePane.empty) {
this._container = L.DomUtil.create('div', 'leaflet-layer', tilePane);
this._setOpacity(this.options.opacity);
}
},
_reset: function() {
this._tiles = {};
this._initContainer();
this._container.innerHTML = '';
},
_update: function() {
var bounds = this._map.getPixelBounds(),
tileSize = this.options.tileSize;
var nwTilePoint = new L.Point(
Math.floor(bounds.min.x / tileSize),
Math.floor(bounds.min.y / tileSize)),
seTilePoint = new L.Point(
Math.floor(bounds.max.x / tileSize),
Math.floor(bounds.max.y / tileSize)),
tileBounds = new L.Bounds(nwTilePoint, seTilePoint);
this._addTilesFromCenterOut(tileBounds);
if (this.options.unloadInvisibleTiles) {
this._removeOtherTiles(tileBounds);
}
},
_addTilesFromCenterOut: function(bounds) {
var queue = [],
center = bounds.getCenter();
for (var j = bounds.min.y; j <= bounds.max.y; j++) {
for (var i = bounds.min.x; i <= bounds.max.x; i++) {
if ((i + ':' + j) in this._tiles) { continue; }
queue.push(new L.Point(i, j));
}
}
// load tiles in order of their distance to center
queue.sort(function(a, b) {
return a.distanceTo(center) - b.distanceTo(center);
});
this._tilesToLoad = queue.length;
for (var k = 0, len = this._tilesToLoad; k < len; k++) {
this._addTile(queue[k]);
}
},
_removeOtherTiles: function(bounds) {
var kArr, x, y, key;
for (key in this._tiles) {
if (this._tiles.hasOwnProperty(key)) {
kArr = key.split(':');
x = parseInt(kArr[0], 10);
y = parseInt(kArr[1], 10);
// remove tile if it's out of bounds
if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {
this._tiles[key].src = '';
if (this._tiles[key].parentNode == this._container) {
this._container.removeChild(this._tiles[key]);
}
delete this._tiles[key];
}
}
}
},
_addTile: function(tilePoint) {
var tilePos = this._getTilePos(tilePoint),
zoom = this._map.getZoom(),
key = tilePoint.x + ':' + tilePoint.y;
// wrap tile coordinates
var tileLimit = (1 << zoom);
if (!this.options.noWrap) {
tilePoint.x = ((tilePoint.x % tileLimit) + tileLimit) % tileLimit;
}
if (tilePoint.y < 0 || tilePoint.y >= tileLimit) { return; }
// create tile
var tile = this._createTile();
L.DomUtil.setPosition(tile, tilePos);
this._tiles[key] = tile;
if (this.options.scheme == 'tms') {
tilePoint.y = tileLimit - tilePoint.y - 1;
}
this._loadTile(tile, tilePoint, zoom);
this._container.appendChild(tile);
},
_getTilePos: function(tilePoint) {
var origin = this._map.getPixelOrigin(),
tileSize = this.options.tileSize;
return tilePoint.multiplyBy(tileSize).subtract(origin);
},
// image-specific code (override to implement e.g. Canvas or SVG tile layer)
getTileUrl: function(tilePoint, zoom) {
var subdomains = this.options.subdomains,
s = this.options.subdomains[(tilePoint.x + tilePoint.y) % subdomains.length];
return this._url
.replace('{s}', s)
.replace('{z}', zoom)
.replace('{x}', tilePoint.x)
.replace('{y}', tilePoint.y);
},
_createTileProto: function() {
this._tileImg = L.DomUtil.create('img', 'leaflet-tile');
this._tileImg.galleryimg = 'no';
var tileSize = this.options.tileSize;
this._tileImg.style.width = tileSize + 'px';
this._tileImg.style.height = tileSize + 'px';
},
_createTile: function() {
var tile = this._tileImg.cloneNode(false);
tile.onselectstart = tile.onmousemove = L.Util.falseFn;
return tile;
},
_loadTile: function(tile, tilePoint, zoom) {
tile._layer = this;
tile.onload = this._tileOnLoad;
tile.onerror = this._tileOnError;
tile.src = this.getTileUrl(tilePoint, zoom);
},
_tileOnLoad: function(e) {
var layer = this._layer;
this.className += ' leaflet-tile-loaded';
layer.fire('tileload', {tile: this, url: this.src});
layer._tilesToLoad--;
if (!layer._tilesToLoad) {
layer.fire('load');
}
},
_tileOnError: function(e) {
var layer = this._layer;
layer.fire('tileerror', {tile: this, url: this.src});
var newUrl = layer.options.errorTileUrl;
if (newUrl) {
this.src = newUrl;
}
}
});

View File

@@ -0,0 +1,51 @@
/*
* L.Circle is a circle overlay (with a certain radius in meters).
*/
L.Circle = L.Path.extend({
initialize: function(latlng, radius, options) {
L.Path.prototype.initialize.call(this, options);
this._latlng = latlng;
this._mRadius = radius;
},
options: {
fill: true
},
setLatLng: function(latlng) {
this._latlng = latlng;
this._redraw();
return this;
},
setRadius: function(radius) {
this._mRadius = radius;
this._redraw();
return this;
},
projectLatlngs: function() {
var equatorLength = 40075017,
scale = this._map.options.scale(this._map._zoom);
this._point = this._map.latLngToLayerPoint(this._latlng);
this._radius = (this._mRadius / equatorLength) * scale;
},
getPathString: function() {
var p = this._point,
r = this._radius;
if (L.Path.SVG) {
return "M" + p.x + "," + (p.y - r) +
"A" + r + "," + r + ",0,1,1," +
(p.x - 0.1) + "," + (p.y - r) + " z";
} else {
p._round();
r = Math.round(r);
return "AL " + p.x + "," + p.y + " " + r + "," + r + " 0," + (65535 * 360);
}
}
});

View File

@@ -0,0 +1,25 @@
/*
* L.CircleMarker is a circle overlay with a permanent pixel radius.
*/
L.CircleMarker = L.Circle.extend({
options: {
radius: 10,
weight: 2
},
initialize: function(latlng, options) {
L.Circle.prototype.initialize.call(this, latlng, null, options);
this._radius = this.options.radius;
},
projectLatlngs: function() {
this._point = this._map.latLngToLayerPoint(this._latlng);
},
setRadius: function(radius) {
this._radius = radius;
this._redraw();
return this;
}
});

View File

@@ -0,0 +1,27 @@
/*
* Contains L.MultiPolyline and L.MultiPolygon layers.
*/
(function() {
function createMulti(klass) {
return L.FeatureGroup.extend({
initialize: function(latlngs, options) {
this._layers = {};
for (var i = 0, len = latlngs.length; i < len; i++) {
this.addLayer(new klass(latlngs[i], options));
}
},
setStyle: function(style) {
for (var i in this._layers) {
if (this._layers.hasOwnProperty(i) && this._layers[i].setStyle) {
this._layers[i].setStyle(style);
}
}
}
});
}
L.MultiPolyline = createMulti(L.Polyline);
L.MultiPolygon = createMulti(L.Polygon);
}());

View File

@@ -0,0 +1,24 @@
/*
* Popup extension to L.Path (polylines, polygons, circles), adding bindPopup method.
*/
L.Path.include({
bindPopup: function(content, options) {
if (!this._popup || this._popup.options !== options) {
this._popup = new L.Popup(options);
}
this._popup.setContent(content);
if (!this._openPopupAdded) {
this.on('click', this._openPopup, this);
this._openPopupAdded = true;
}
return this;
},
_openPopup: function(e) {
this._popup.setLatLng(e.latlng);
this._map.openPopup(this._popup);
}
});

View File

@@ -0,0 +1,91 @@
/*
* Vector rendering for IE6-8 through VML.
* Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
*/
L.Path.VML = (function() {
var d = document.createElement('div'), s;
d.innerHTML = '<v:shape adj="1"/>';
s = d.firstChild;
s.style.behavior = 'url(#default#VML)';
return (s && (typeof s.adj == 'object'));
})();
L.Path = L.Path.SVG || !L.Path.VML ? L.Path : L.Path.extend({
statics: {
CLIP_PADDING: 0.02
},
_createElement: (function() {
try {
document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
return function(name) {
return document.createElement('<lvml:' + name + ' class="lvml">');
};
} catch (e) {
return function(name) {
return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
};
}
})(),
_initRoot: function() {
if (!this._map._pathRoot) {
this._map._pathRoot = document.createElement('div');
this._map._pathRoot.className = 'leaflet-vml-container';
this._map._panes.overlayPane.appendChild(this._map._pathRoot);
this._map.on('moveend', this._updateViewport, this);
this._updateViewport();
}
},
_initPath: function() {
this._container = this._createElement('shape');
this._container.className += ' leaflet-vml-shape' +
(this.options.clickable ? ' leaflet-clickable' : '');
this._container.coordsize = '1 1';
this._path = this._createElement('path');
this._container.appendChild(this._path);
this._map._pathRoot.appendChild(this._container);
},
_initStyle: function() {
if (this.options.stroke) {
this._stroke = this._createElement('stroke');
this._stroke.endcap = 'round';
this._container.appendChild(this._stroke);
} else {
this._container.stroked = false;
}
if (this.options.fill) {
this._container.filled = true;
this._fill = this._createElement('fill');
this._container.appendChild(this._fill);
} else {
this._container.filled = false;
}
this._updateStyle();
},
_updateStyle: function() {
if (this.options.stroke) {
this._stroke.weight = this.options.weight + 'px';
this._stroke.color = this.options.color;
this._stroke.opacity = this.options.opacity;
}
if (this.options.fill) {
this._fill.color = this.options.fillColor || this.options.color;
this._fill.opacity = this.options.fillOpacity;
}
},
_updatePath: function() {
this._container.style.display = 'none';
this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug
this._container.style.display = '';
}
});

View File

@@ -0,0 +1,207 @@
/*
* L.Path is a base class for rendering vector paths on a map. It's inherited by Polyline, Circle, etc.
*/
L.Path = L.Class.extend({
includes: [L.Mixin.Events],
statics: (function() {
var svgns = 'http://www.w3.org/2000/svg',
ce = 'createElementNS';
return {
SVG_NS: svgns,
SVG: !!(document[ce] && document[ce](svgns, 'svg').createSVGRect),
// how much to extend the clip area around the map view
// (relative to its size, e.g. 0.5 is half the screen in each direction)
CLIP_PADDING: 0.5
};
})(),
options: {
stroke: true,
color: '#0033ff',
weight: 5,
opacity: 0.5,
fill: false,
fillColor: null, //same as color by default
fillOpacity: 0.2,
clickable: true,
updateOnMoveEnd: false
},
initialize: function(options) {
L.Util.setOptions(this, options);
},
onAdd: function(map) {
this._map = map;
this._initElements();
this._initEvents();
this.projectLatlngs();
this._updatePath();
map.on('viewreset', this.projectLatlngs, this);
this._updateTrigger = this.options.updateOnMoveEnd ? 'moveend' : 'viewreset';
map.on(this._updateTrigger, this._updatePath, this);
},
onRemove: function(map) {
map._pathRoot.removeChild(this._container);
map.off('viewreset', this._projectLatlngs, this);
map.off(this._updateTrigger, this._updatePath, this);
},
projectLatlngs: function() {
// do all projection stuff here
},
getPathString: function() {
// form path string here
},
setStyle: function(style) {
L.Util.setOptions(this, style);
if (this._path) {
this._updateStyle();
}
},
_initElements: function() {
this._initRoot();
this._initPath();
this._initStyle();
},
_initRoot: function() {
if (!this._map._pathRoot) {
this._map._pathRoot = this._createElement('svg');
this._map._panes.overlayPane.appendChild(this._map._pathRoot);
this._map.on('moveend', this._updateSvgViewport, this);
this._updateSvgViewport();
}
},
_updateSvgViewport: function() {
this._updateViewport();
var vp = this._map._pathViewport,
min = vp.min,
max = vp.max,
width = max.x - min.x,
height = max.y - min.y,
root = this._map._pathRoot,
pane = this._map._panes.overlayPane;
// Hack to make flicker on drag end on mobile webkit less irritating
// Unfortunately I haven't found a good workaround for this yet
if (L.Browser.mobileWebkit) { pane.removeChild(root); }
L.DomUtil.setPosition(root, min);
root.setAttribute('width', width);
root.setAttribute('height', height);
root.setAttribute('viewBox', [min.x, min.y, width, height].join(' '));
if (L.Browser.mobileWebkit) { pane.appendChild(root); }
},
_updateViewport: function() {
var p = L.Path.CLIP_PADDING,
size = this._map.getSize(),
//TODO this._map._getMapPanePos()
panePos = L.DomUtil.getPosition(this._map._mapPane),
min = panePos.multiplyBy(-1).subtract(size.multiplyBy(p)),
max = min.add(size.multiplyBy(1 + p * 2));
this._map._pathViewport = new L.Bounds(min, max);
},
_initPath: function() {
this._container = this._createElement('g');
this._path = this._createElement('path');
this._container.appendChild(this._path);
this._map._pathRoot.appendChild(this._container);
},
_initStyle: function() {
if (this.options.stroke) {
this._path.setAttribute('stroke-linejoin', 'round');
this._path.setAttribute('stroke-linecap', 'round');
}
if (this.options.fill) {
this._path.setAttribute('fill-rule', 'evenodd');
} else {
this._path.setAttribute('fill', 'none');
}
this._updateStyle();
},
_updateStyle: function() {
if (this.options.stroke) {
this._path.setAttribute('stroke', this.options.color);
this._path.setAttribute('stroke-opacity', this.options.opacity);
this._path.setAttribute('stroke-width', this.options.weight);
}
if (this.options.fill) {
this._path.setAttribute('fill', this.options.fillColor || this.options.color);
this._path.setAttribute('fill-opacity', this.options.fillOpacity);
}
},
_updatePath: function() {
var str = this.getPathString();
if (!str) {
// fix webkit empty string parsing bug
str = 'M0 0';
}
this._path.setAttribute('d', str);
},
_createElement: function(name) {
return document.createElementNS(L.Path.SVG_NS, name);
},
// TODO remove duplication with L.Map
_initEvents: function() {
if (this.options.clickable) {
if (!L.Path.VML) {
this._path.setAttribute('class', 'leaflet-clickable');
}
L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this);
var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];
for (var i = 0; i < events.length; i++) {
L.DomEvent.addListener(this._container, events[i], this._fireMouseEvent, this);
}
}
},
_onMouseClick: function(e) {
if (this._map.dragging && this._map.dragging.moved()) { return; }
this._fireMouseEvent(e);
},
_fireMouseEvent: function(e) {
if (!this.hasEventListeners(e.type)) { return; }
this.fire(e.type, {
latlng: this._map.mouseEventToLatLng(e),
layerPoint: this._map.mouseEventToLayerPoint(e)
});
L.DomEvent.stopPropagation(e);
},
_redraw: function() {
this.projectLatlngs();
this._updatePath();
}
});

View File

@@ -0,0 +1,58 @@
/*
* L.Polygon is used to display polygons on a map.
*/
L.Polygon = L.Polyline.extend({
options: {
fill: true
},
initialize: function(latlngs, options) {
L.Polyline.prototype.initialize.call(this, latlngs, options);
if (latlngs[0] instanceof Array) {
this._latlngs = latlngs[0];
this._holes = latlngs.slice(1);
}
},
projectLatlngs: function() {
L.Polyline.prototype.projectLatlngs.call(this);
// project polygon holes points
// TODO move this logic to Polyline to get rid of duplication
this._holePoints = [];
if (!this._holes) return;
for (var i = 0, len = this._holes.length, hole; i < len; i++) {
this._holePoints[i] = [];
for(var j = 0, len2 = this._holes[i].length; j < len2; j++) {
this._holePoints[i][j] = this._map.latLngToLayerPoint(this._holes[i][j]);
}
}
},
_clipPoints: function() {
var points = this._originalPoints,
newParts = [];
this._parts = [points].concat(this._holePoints);
if (this.options.noClip) return;
for (var i = 0, len = this._parts.length; i < len; i++) {
var clipped = L.PolyUtil.clipPolygon(this._parts[i], this._map._pathViewport);
if (!clipped.length) continue;
newParts.push(clipped);
}
this._parts = newParts;
},
_getPathPartStr: function(points) {
var str = L.Polyline.prototype._getPathPartStr.call(this, points);
return str + (L.Path.SVG ? 'z' : 'x');
}
});

View File

@@ -0,0 +1,112 @@
L.Polyline = L.Path.extend({
initialize: function(latlngs, options) {
L.Path.prototype.initialize.call(this, options);
this._latlngs = latlngs;
},
options: {
// how much to simplify the polyline on each zoom level
// more = better performance and smoother look, less = more accurate
smoothFactor: 1.0,
noClip: false,
updateOnMoveEnd: true
},
projectLatlngs: function() {
this._originalPoints = [];
for (var i = 0, len = this._latlngs.length; i < len; i++) {
this._originalPoints[i] = this._map.latLngToLayerPoint(this._latlngs[i]);
}
},
getPathString: function() {
for (var i = 0, len = this._parts.length, str = ''; i < len; i++) {
str += this._getPathPartStr(this._parts[i]);
}
return str;
},
getLatLngs: function() {
return this._latlngs;
},
setLatLngs: function(latlngs) {
this._latlngs = latlngs;
this._redraw();
return this;
},
addLatLng: function(latlng) {
this._latlngs.push(latlng);
this._redraw();
return this;
},
spliceLatLngs: function(index, howMany) {
var removed = [].splice.apply(this._latlngs, arguments);
this._redraw();
return removed;
},
_getPathPartStr: function(points) {
var round = L.Path.VML;
for (var j = 0, len2 = points.length, str = '', p; j < len2; j++) {
p = points[j];
if (round) p._round();
str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
}
return str;
},
_clipPoints: function() {
var points = this._originalPoints,
len = points.length,
i, k, segment;
if (this.options.noClip) {
this._parts = [points];
return;
}
this._parts = [];
var parts = this._parts,
vp = this._map._pathViewport,
lu = L.LineUtil;
for (i = 0, k = 0; i < len - 1; i++) {
segment = lu.clipSegment(points[i], points[i+1], vp, i);
if (!segment) continue;
parts[k] = parts[k] || [];
parts[k].push(segment[0]);
// if segment goes out of screen, or it's the last one, it's the end of the line part
if ((segment[1] != points[i+1]) || (i == len - 2)) {
parts[k].push(segment[1]);
k++;
}
}
},
// simplify each clipped part of the polyline
_simplifyPoints: function() {
var parts = this._parts,
lu = L.LineUtil;
for (var i = 0, len = parts.length; i < len; i++) {
parts[i] = lu.simplify(parts[i], this.options.smoothFactor);
}
},
_updatePath: function() {
this._clipPoints();
this._simplifyPoints();
L.Path.prototype._updatePath.call(this);
}
});