build to single distributables with gulp, check-in dist not bower_components

This commit is contained in:
Norbert Renner 2015-03-29 18:55:02 +02:00
parent 650bacd915
commit b808fbe44e
143 changed files with 577 additions and 95319 deletions

11
.gitignore vendored
View file

@ -1,11 +1,4 @@
bower_components/leaflet-routing/libs/ bower_components/
bower_components/leaflet-routing/examples/ node_modules/
bower_components/Leaflet.Elevation/*
!bower_components/Leaflet.Elevation/dist/
!bower_components/Leaflet.Elevation/src/
bower_components/async/*
!bower_components/async/lib/
!bower_components/async/README.md
!bower_components/async/LICENSE
nbproject/ nbproject/
.idea/ .idea/

View file

@ -48,7 +48,27 @@ This is needed for pre-loading the selected profile (unless you allowed local fi
python -m SimpleHTTPServer python -m SimpleHTTPServer
2. open http://localhost:8000/brouter-web/ 2. open http://localhost:8000/brouter-web/
## Build
Requires [Node and npm](http://nodejs.org/) (or [io.js](https://iojs.org)), [Bower](http://bower.io/) and [Gulp](http://gulpjs.com/):
npm install -g bower
npm install -g gulp
Install:
npm install
bower install
Build:
gulp
Develop:
gulp watch
## License ## License

View file

@ -1,16 +1,71 @@
{ {
"name": "brouter-web", "name": "brouter-web",
"version": "0.1.0", "version": "0.5.0",
"main": "js/index.js", "main": "dist/**/*",
"ignore": [ "ignore": [
"**/.*", "**/.*",
"bower_components" "bower_components"
], ],
"dependencies": { "dependencies": {
"leaflet": "~0.7.3",
"leaflet-search": "*", "leaflet-search": "*",
"leaflet-plugins": "*", "leaflet-plugins": "~1.3.2",
"leaflet-routing": "nrenner/leaflet-routing#styles", "leaflet-routing": "Turistforeningen/leaflet-routing#gh-pages",
"Leaflet.Elevation": "MrMufflon/Leaflet.Elevation#master", "async": "~0.9.2",
"async": "*" "d3": "~3.5.5",
"leaflet.draw": "~0.2.3",
"bootstrap": "~3.3.4",
"DataTables": "~1.10.5",
"Leaflet.Elevation": "MrMufflon/Leaflet.Elevation#master"
},
"overrides": {
"leaflet": {
"main": [
"dist/leaflet-src.js",
"dist/leaflet.css",
"dist/images/*.png"
]
},
"leaflet-search": {
"main": [
"dist/leaflet-search.src.js",
"dist/leaflet-search.min.css",
"images/*.+(png|gif)"
]
},
"leaflet-plugins": {
"main": [
"control/Permalink.js",
"control/Permalink.Layer.js",
"layer/tile/Bing.js"
]
},
"leaflet-routing": {
"main": [
"src/utils/LineUtil.Snapping.js",
"src/utils/Marker.Snapping.js",
"src/L.Routing.js",
"src/L.Routing.Draw.js",
"src/L.Routing.Edit.js"
]
},
"leaflet.draw": {
"main": [
"dist/leaflet.draw-src.js",
"dist/leaflet.draw.css",
"dist/images/*.png"
]
},
"bootstrap": {
"main": [
"dist/js/bootstrap.js",
"dist/css/bootstrap.css",
"dist/css/bootstrap-theme.css",
"dist/fonts/*"
]
},
"Leaflet.Elevation": {
"dependencies": null
}
} }
} }

View file

@ -1 +0,0 @@
.lime-theme .leaflet-control.elevation .background{background-color:rgba(156,194,34,.2);-webkit-border-radius:5px;-moz-border-radius:5px;-ms-border-radius:5px;-o-border-radius:5px;border-radius:5px}.lime-theme .leaflet-control.elevation .axis line,.lime-theme .leaflet-control.elevation .axis path{fill:none;stroke:#566b13;stroke-width:2}.lime-theme .leaflet-control.elevation .area{fill:#9cc222}.lime-theme .leaflet-control.elevation .mouse-focus-line{pointer-events:none;stroke-width:1;stroke:#101404}.lime-theme .leaflet-control.elevation .elevation-toggle{cursor:pointer;box-shadow:0 1px 7px rgba(0,0,0,.4);-webkit-border-radius:5px;border-radius:5px;width:36px;height:36px;background:url(images/elevation.png) no-repeat center center #f8f8f9}.lime-theme .leaflet-control.elevation-collapsed .background{display:none}.lime-theme .leaflet-control.elevation-collapsed .elevation-toggle{display:block}.lime-theme .leaflet-control.elevation .mouse-drag{fill:rgba(99,126,11,.4)}.lime-theme .leaflet-overlay-pane .height-focus{stroke:#9cc222;fill:#9cc222}.lime-theme .leaflet-overlay-pane .height-focus.line{pointer-events:none;stroke-width:2}.steelblue-theme .leaflet-control.elevation .background{background-color:rgba(70,130,180,.2);-webkit-border-radius:5px;-moz-border-radius:5px;-ms-border-radius:5px;-o-border-radius:5px;border-radius:5px}.steelblue-theme .leaflet-control.elevation .axis line,.steelblue-theme .leaflet-control.elevation .axis path{fill:none;stroke:#0d1821;stroke-width:2}.steelblue-theme .leaflet-control.elevation .area{fill:#4682b4}.steelblue-theme .leaflet-control.elevation .mouse-focus-line{pointer-events:none;stroke-width:1;stroke:#0d1821}.steelblue-theme .leaflet-control.elevation .elevation-toggle{cursor:pointer;box-shadow:0 1px 7px rgba(0,0,0,.4);-webkit-border-radius:5px;border-radius:5px;width:36px;height:36px;background:url(images/elevation.png) no-repeat center center #f8f8f9}.steelblue-theme .leaflet-control.elevation-collapsed .background{display:none}.steelblue-theme .leaflet-control.elevation-collapsed .elevation-toggle{display:block}.steelblue-theme .leaflet-control.elevation .mouse-drag{fill:rgba(23,74,117,.4)}.steelblue-theme .leaflet-overlay-pane .height-focus{stroke:#4682b4;fill:#4682b4}.steelblue-theme .leaflet-overlay-pane .height-focus.line{pointer-events:none;stroke-width:2}.purple-theme .leaflet-control.elevation .background{background-color:rgba(115,44,123,.2);-webkit-border-radius:5px;-moz-border-radius:5px;-ms-border-radius:5px;-o-border-radius:5px;border-radius:5px}.purple-theme .leaflet-control.elevation .axis line,.purple-theme .leaflet-control.elevation .axis path{fill:none;stroke:#2d1130;stroke-width:2}.purple-theme .leaflet-control.elevation .area{fill:#732c7b}.purple-theme .leaflet-control.elevation .mouse-focus-line{pointer-events:none;stroke-width:1;stroke:#000}.purple-theme .leaflet-control.elevation .elevation-toggle{cursor:pointer;box-shadow:0 1px 7px rgba(0,0,0,.4);-webkit-border-radius:5px;border-radius:5px;width:36px;height:36px;background:url(images/elevation.png) no-repeat center center #f8f8f9}.purple-theme .leaflet-control.elevation-collapsed .background{display:none}.purple-theme .leaflet-control.elevation-collapsed .elevation-toggle{display:block}.purple-theme .leaflet-control.elevation .mouse-drag{fill:rgba(74,14,80,.4)}.purple-theme .leaflet-overlay-pane .height-focus{stroke:#732c7b;fill:#732c7b}.purple-theme .leaflet-overlay-pane .height-focus.line{pointer-events:none;stroke-width:2}

File diff suppressed because one or more lines are too long

View file

@ -1,675 +0,0 @@
L.Control.Elevation = L.Control.extend({
options: {
position: "topright",
theme: "lime-theme",
width: 600,
height: 175,
margins: {
top: 10,
right: 20,
bottom: 30,
left: 60
},
useHeightIndicator: true,
interpolation: "linear",
hoverNumber: {
decimalsX: 3,
decimalsY: 0,
formatter: undefined
},
xTicks: undefined,
yTicks: undefined,
collapsed: false,
yAxisMin: undefined,
yAxisMax: undefined,
forceAxisBounds: false
},
onRemove: function(map) {
this._container = null;
},
onAdd: function(map) {
this._map = map;
var opts = this.options;
var margin = opts.margins;
opts.xTicks = opts.xTicks || Math.round(this._width() / 75);
opts.yTicks = opts.yTicks || Math.round(this._height() / 30);
opts.hoverNumber.formatter = opts.hoverNumber.formatter || this._formatter;
//append theme name on body
d3.select("body").classed(opts.theme, true);
var x = this._x = d3.scale.linear()
.range([0, this._width()]);
var y = this._y = d3.scale.linear()
.range([this._height(), 0]);
var area = this._area = d3.svg.area()
.interpolate(opts.interpolation)
.x(function(d) {
return x(d.dist);
})
.y0(this._height())
.y1(function(d) {
return y(d.altitude);
});
var container = this._container = L.DomUtil.create("div", "elevation");
this._initToggle();
var cont = d3.select(container);
cont.attr("width", opts.width);
var svg = cont.append("svg");
svg.attr("width", opts.width)
.attr("class", "background")
.attr("height", opts.height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var line = d3.svg.line();
line = line
.x(function(d) {
return d3.mouse(svg.select("g"))[0];
})
.y(function(d) {
return this._height();
});
var g = d3.select(this._container).select("svg").select("g");
this._areapath = g.append("path")
.attr("class", "area");
var background = this._background = g.append("rect")
.attr("width", this._width())
.attr("height", this._height())
.style("fill", "none")
.style("stroke", "none")
.style("pointer-events", "all");
if (L.Browser.touch) {
background.on("touchmove.drag", this._dragHandler.bind(this)).
on("touchstart.drag", this._dragStartHandler.bind(this)).
on("touchstart.focus", this._mousemoveHandler.bind(this));
L.DomEvent.on(this._container, 'touchend', this._dragEndHandler, this);
} else {
background.on("mousemove.focus", this._mousemoveHandler.bind(this)).
on("mouseout.focus", this._mouseoutHandler.bind(this)).
on("mousedown.drag", this._dragStartHandler.bind(this)).
on("mousemove.drag", this._dragHandler.bind(this));
L.DomEvent.on(this._container, 'mouseup', this._dragEndHandler, this);
}
this._xaxisgraphicnode = g.append("g");
this._yaxisgraphicnode = g.append("g");
this._appendXaxis(this._xaxisgraphicnode);
this._appendYaxis(this._yaxisgraphicnode);
var focusG = this._focusG = g.append("g");
this._mousefocus = focusG.append('svg:line')
.attr('class', 'mouse-focus-line')
.attr('x2', '0')
.attr('y2', '0')
.attr('x1', '0')
.attr('y1', '0');
this._focuslabelX = focusG.append("svg:text")
.style("pointer-events", "none")
.attr("class", "mouse-focus-label-x");
this._focuslabelY = focusG.append("svg:text")
.style("pointer-events", "none")
.attr("class", "mouse-focus-label-y");
if (this._data) {
this._applyData();
}
return container;
},
_dragHandler: function() {
//we don´t want map events to occur here
d3.event.preventDefault();
d3.event.stopPropagation();
this._gotDragged = true;
this._drawDragRectangle();
},
/*
* Draws the currently dragged rectabgle over the chart.
*/
_drawDragRectangle: function() {
if (!this._dragStartCoords) {
return;
}
var dragEndCoords = this._dragCurrentCoords = d3.mouse(this._background.node());
var x1 = Math.min(this._dragStartCoords[0], dragEndCoords[0]),
x2 = Math.max(this._dragStartCoords[0], dragEndCoords[0]);
if (!this._dragRectangle && !this._dragRectangleG) {
var g = d3.select(this._container).select("svg").select("g");
this._dragRectangleG = g.append("g");
this._dragRectangle = this._dragRectangleG.append("rect")
.attr("width", x2 - x1)
.attr("height", this._height())
.attr("x", x1)
.attr('class', 'mouse-drag')
.style("pointer-events", "none");
} else {
this._dragRectangle.attr("width", x2 - x1)
.attr("x", x1);
}
},
/*
* Removes the drag rectangle and zoms back to the total extent of the data.
*/
_resetDrag: function() {
if (this._dragRectangleG) {
this._dragRectangleG.remove();
this._dragRectangleG = null;
this._dragRectangle = null;
this._hidePositionMarker();
this._map.fitBounds(this._fullExtent);
}
},
/*
* Handles end of dragg operations. Zooms the map to the selected items extent.
*/
_dragEndHandler: function() {
if (!this._dragStartCoords || !this._gotDragged) {
this._dragStartCoords = null;
this._gotDragged = false;
this._resetDrag();
return;
}
this._hidePositionMarker();
var item1 = this._findItemForX(this._dragStartCoords[0]),
item2 = this._findItemForX(this._dragCurrentCoords[0]);
this._fitSection(item1, item2);
this._dragStartCoords = null;
this._gotDragged = false;
},
_dragStartHandler: function() {
d3.event.preventDefault();
d3.event.stopPropagation();
this._gotDragged = false;
this._dragStartCoords = d3.mouse(this._background.node());
},
/*
* Finds a data entry for a given x-coordinate of the diagram
*/
_findItemForX: function(x) {
var bisect = d3.bisector(function(d) {
return d.dist;
}).left;
var xinvert = this._x.invert(x);
return bisect(this._data, xinvert);
},
/** Make the map fit the route section between given indexes. */
_fitSection: function(index1, index2) {
var start = Math.min(index1, index2),
end = Math.max(index1, index2);
var ext = this._calculateFullExtent(this._data.slice(start, end));
this._map.fitBounds(ext);
},
_initToggle: function() {
/* inspired by L.Control.Layers */
var container = this._container;
//Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
container.setAttribute('aria-haspopup', true);
if (!L.Browser.touch) {
L.DomEvent
.disableClickPropagation(container);
//.disableScrollPropagation(container);
} else {
L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
}
if (this.options.collapsed) {
this._collapse();
if (!L.Browser.android) {
L.DomEvent
.on(container, 'mouseover', this._expand, this)
.on(container, 'mouseout', this._collapse, this);
}
var link = this._button = L.DomUtil.create('a', 'elevation-toggle', container);
link.href = '#';
link.title = 'Elevation';
if (L.Browser.touch) {
L.DomEvent
.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', this._expand, this);
} else {
L.DomEvent.on(link, 'focus', this._expand, this);
}
this._map.on('click', this._collapse, this);
// TODO keyboard accessibility
}
},
_expand: function() {
this._container.className = this._container.className.replace(' elevation-collapsed', '');
},
_collapse: function() {
L.DomUtil.addClass(this._container, 'elevation-collapsed');
},
_width: function() {
var opts = this.options;
return opts.width - opts.margins.left - opts.margins.right;
},
_height: function() {
var opts = this.options;
return opts.height - opts.margins.top - opts.margins.bottom;
},
/*
* Fromatting funciton using the given decimals and seperator
*/
_formatter: function(num, dec, sep) {
var res;
if (dec === 0) {
res = Math.round(num) + "";
} else {
res = L.Util.formatNum(num, dec) + "";
}
var numbers = res.split(".");
if (numbers[1]) {
var d = dec - numbers[1].length;
for (; d > 0; d--) {
numbers[1] += "0";
}
res = numbers.join(sep || ".");
}
return res;
},
_appendYaxis: function(y) {
y.attr("class", "y axis")
.call(d3.svg.axis()
.scale(this._y)
.ticks(this.options.yTicks)
.orient("left"))
.append("text")
.attr("x", -45)
.attr("y", 3)
.style("text-anchor", "end")
.text("m");
},
_appendXaxis: function(x) {
x.attr("class", "x axis")
.attr("transform", "translate(0," + this._height() + ")")
.call(d3.svg.axis()
.scale(this._x)
.ticks(this.options.xTicks)
.orient("bottom"))
.append("text")
.attr("x", this._width() + 20)
.attr("y", 15)
.style("text-anchor", "end")
.text("km");
},
_updateAxis: function() {
this._xaxisgraphicnode.selectAll("g").remove();
this._xaxisgraphicnode.selectAll("path").remove();
this._xaxisgraphicnode.selectAll("text").remove();
this._yaxisgraphicnode.selectAll("g").remove();
this._yaxisgraphicnode.selectAll("path").remove();
this._yaxisgraphicnode.selectAll("text").remove();
this._appendXaxis(this._xaxisgraphicnode);
this._appendYaxis(this._yaxisgraphicnode);
},
_mouseoutHandler: function() {
this._hidePositionMarker();
},
/*
* Hides the position-/heigth indication marker drawn onto the map
*/
_hidePositionMarker: function() {
if (this._marker) {
this._map.removeLayer(this._marker);
this._marker = null;
}
if (this._mouseHeightFocus) {
this._mouseHeightFocus.style("visibility", "hidden");
this._mouseHeightFocusLabel.style("visibility", "hidden");
}
if (this._pointG) {
this._pointG.style("visibility", "hidden");
}
this._focusG.style("visibility", "hidden");
},
/*
* Handles the moueseover the chart and displays distance and altitude level
*/
_mousemoveHandler: function(d, i, ctx) {
if (!this._data || this._data.length === 0) {
return;
}
var coords = d3.mouse(this._background.node());
var opts = this.options;
this._focusG.style("visibility", "visible");
this._mousefocus.attr('x1', coords[0])
.attr('y1', 0)
.attr('x2', coords[0])
.attr('y2', this._height())
.classed('hidden', false);
var bisect = d3.bisector(function(d) {
return d.dist;
}).left;
var item = this._data[this._findItemForX(coords[0])],
alt = item.altitude,
dist = item.dist,
ll = item.latlng,
numY = opts.hoverNumber.formatter(alt, opts.hoverNumber.decimalsY),
numX = opts.hoverNumber.formatter(dist, opts.hoverNumber.decimalsX);
this._focuslabelX.attr("x", coords[0])
.text(numY + " m");
this._focuslabelY.attr("y", this._height() - 5)
.attr("x", coords[0])
.text(numX + " km");
var layerpoint = this._map.latLngToLayerPoint(ll);
//if we use a height indicator we create one with SVG
//otherwise we show a marker
if (opts.useHeightIndicator) {
if (!this._mouseHeightFocus) {
var heightG = d3.select(".leaflet-overlay-pane svg")
.append("g");
this._mouseHeightFocus = heightG.append('svg:line')
.attr('class', 'height-focus line')
.attr('x2', '0')
.attr('y2', '0')
.attr('x1', '0')
.attr('y1', '0');
var pointG = this._pointG = heightG.append("g");
pointG.append("svg:circle")
.attr("r", 6)
.attr("cx", 0)
.attr("cy", 0)
.attr("class", "height-focus circle-lower");
this._mouseHeightFocusLabel = heightG.append("svg:text")
.attr("class", "height-focus-label")
.style("pointer-events", "none");
}
var normalizedAlt = this._height() / this._maxElevation * alt;
var normalizedY = layerpoint.y - normalizedAlt;
this._mouseHeightFocus.attr("x1", layerpoint.x)
.attr("x2", layerpoint.x)
.attr("y1", layerpoint.y)
.attr("y2", normalizedY)
.style("visibility", "visible");
this._pointG.attr("transform", "translate(" + layerpoint.x + "," + layerpoint.y + ")")
.style("visibility", "visible");
this._mouseHeightFocusLabel.attr("x", layerpoint.x)
.attr("y", normalizedY)
.text(alt + " m")
.style("visibility", "visible");
} else {
if (!this._marker) {
this._marker = new L.Marker(ll).addTo(this._map);
} else {
this._marker.setLatLng(ll);
}
}
},
/*
* Parsing of GeoJSON data lines and their elevation in z-coordinate
*/
_addGeoJSONData: function(coords) {
if (coords) {
var data = this._data || [];
var dist = this._dist || 0;
var ele = this._maxElevation || 0;
for (var i = 0; i < coords.length; i++) {
var s = new L.LatLng(coords[i][1], coords[i][0]);
var e = new L.LatLng(coords[i ? i - 1 : 0][1], coords[i ? i - 1 : 0][0]);
var newdist = s.distanceTo(e);
dist = dist + Math.round(newdist / 1000 * 100000) / 100000;
ele = ele < coords[i][2] ? coords[i][2] : ele;
data.push({
dist: dist,
altitude: coords[i][2],
x: coords[i][0],
y: coords[i][1],
latlng: s
});
}
this._dist = dist;
this._data = data;
this._maxElevation = ele;
}
},
/*
* Parsing function for GPX data as used by https://github.com/mpetazzoni/leaflet-gpx
*/
_addGPXdata: function(coords) {
if (coords) {
var data = this._data || [];
var dist = this._dist || 0;
var ele = this._maxElevation || 0;
for (var i = 0; i < coords.length; i++) {
var s = coords[i];
var e = coords[i ? i - 1 : 0];
var newdist = s.distanceTo(e);
dist = dist + Math.round(newdist / 1000 * 100000) / 100000;
ele = ele < s.meta.ele ? s.meta.ele : ele;
data.push({
dist: dist,
altitude: s.meta.ele,
x: s.lng,
y: s.lat,
latlng: s
});
}
this._dist = dist;
this._data = data;
this._maxElevation = ele;
}
},
_addData: function(d) {
var geom = d && d.geometry && d.geometry;
var i;
if (geom) {
switch (geom.type) {
case 'LineString':
this._addGeoJSONData(geom.coordinates);
break;
case 'MultiLineString':
for (i = 0; i < geom.coordinates.length; i++) {
this._addGeoJSONData(geom.coordinates[i]);
}
break;
default:
throw new Error('Invalid GeoJSON object.');
}
}
var feat = d && d.type === "FeatureCollection";
if (feat) {
for (i = 0; i < d.features.length; i++) {
this._addData(d.features[i]);
}
}
if (d && d._latlngs) {
this._addGPXdata(d._latlngs);
}
},
/*
* Calculates the full extent of the data array
*/
_calculateFullExtent: function(data) {
if (!data || data.length < 1) {
throw new Error("no data in parameters");
}
var ext = new L.latLngBounds(data[0].latlng, data[0].latlng);
data.forEach(function(item) {
ext.extend(item.latlng);
});
return ext;
},
/*
* Add data to the diagram either from GPX or GeoJSON and
* update the axis domain and data
*/
addData: function(d) {
this._addData(d);
if (this._container) {
this._applyData();
}
},
_applyData: function() {
var xdomain = d3.extent(this._data, function(d) {
return d.dist;
});
var ydomain = d3.extent(this._data, function(d) {
return d.altitude;
});
var opts = this.options;
if (opts.yAxisMin !== undefined && (opts.yAxisMin < ydomain[0] || opts.forceAxisBounds)) {
ydomain[0] = opts.yAxisMin;
}
if (opts.yAxisMax !== undefined && (opts.yAxisMax > ydomain[1] || opts.forceAxisBounds)) {
ydomain[1] = opts.yAxisMax;
}
this._x.domain(xdomain);
this._y.domain(ydomain);
this._areapath.datum(this._data)
.attr("d", this._area);
this._updateAxis();
this._fullExtent = this._calculateFullExtent(this._data);
},
/*
* Reset data
*/
_clearData: function() {
this._data = null;
this._dist = null;
this._maxElevation = null;
},
/*
* Reset data and display
*/
clear: function() {
this._clearData();
if (!this._areapath) {
return;
}
// workaround for 'Error: Problem parsing d=""' in Webkit when empty data
// https://groups.google.com/d/msg/d3-js/7rFxpXKXFhI/HzIO_NPeDuMJ
//this._areapath.datum(this._data).attr("d", this._area);
this._areapath.attr("d", "M0 0");
this._x.domain([0, 1]);
this._y.domain([0, 1]);
this._updateAxis();
}
});
L.control.elevation = function(options) {
return new L.Control.Elevation(options);
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 683 B

View file

@ -1,675 +0,0 @@
L.Control.Elevation = L.Control.extend({
options: {
position: "topright",
theme: "lime-theme",
width: 600,
height: 175,
margins: {
top: 10,
right: 20,
bottom: 30,
left: 60
},
useHeightIndicator: true,
interpolation: "linear",
hoverNumber: {
decimalsX: 3,
decimalsY: 0,
formatter: undefined
},
xTicks: undefined,
yTicks: undefined,
collapsed: false,
yAxisMin: undefined,
yAxisMax: undefined,
forceAxisBounds: false
},
onRemove: function(map) {
this._container = null;
},
onAdd: function(map) {
this._map = map;
var opts = this.options;
var margin = opts.margins;
opts.xTicks = opts.xTicks || Math.round(this._width() / 75);
opts.yTicks = opts.yTicks || Math.round(this._height() / 30);
opts.hoverNumber.formatter = opts.hoverNumber.formatter || this._formatter;
//append theme name on body
d3.select("body").classed(opts.theme, true);
var x = this._x = d3.scale.linear()
.range([0, this._width()]);
var y = this._y = d3.scale.linear()
.range([this._height(), 0]);
var area = this._area = d3.svg.area()
.interpolate(opts.interpolation)
.x(function(d) {
return x(d.dist);
})
.y0(this._height())
.y1(function(d) {
return y(d.altitude);
});
var container = this._container = L.DomUtil.create("div", "elevation");
this._initToggle();
var cont = d3.select(container);
cont.attr("width", opts.width);
var svg = cont.append("svg");
svg.attr("width", opts.width)
.attr("class", "background")
.attr("height", opts.height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var line = d3.svg.line();
line = line
.x(function(d) {
return d3.mouse(svg.select("g"))[0];
})
.y(function(d) {
return this._height();
});
var g = d3.select(this._container).select("svg").select("g");
this._areapath = g.append("path")
.attr("class", "area");
var background = this._background = g.append("rect")
.attr("width", this._width())
.attr("height", this._height())
.style("fill", "none")
.style("stroke", "none")
.style("pointer-events", "all");
if (L.Browser.touch) {
background.on("touchmove.drag", this._dragHandler.bind(this)).
on("touchstart.drag", this._dragStartHandler.bind(this)).
on("touchstart.focus", this._mousemoveHandler.bind(this));
L.DomEvent.on(this._container, 'touchend', this._dragEndHandler, this);
} else {
background.on("mousemove.focus", this._mousemoveHandler.bind(this)).
on("mouseout.focus", this._mouseoutHandler.bind(this)).
on("mousedown.drag", this._dragStartHandler.bind(this)).
on("mousemove.drag", this._dragHandler.bind(this));
L.DomEvent.on(this._container, 'mouseup', this._dragEndHandler, this);
}
this._xaxisgraphicnode = g.append("g");
this._yaxisgraphicnode = g.append("g");
this._appendXaxis(this._xaxisgraphicnode);
this._appendYaxis(this._yaxisgraphicnode);
var focusG = this._focusG = g.append("g");
this._mousefocus = focusG.append('svg:line')
.attr('class', 'mouse-focus-line')
.attr('x2', '0')
.attr('y2', '0')
.attr('x1', '0')
.attr('y1', '0');
this._focuslabelX = focusG.append("svg:text")
.style("pointer-events", "none")
.attr("class", "mouse-focus-label-x");
this._focuslabelY = focusG.append("svg:text")
.style("pointer-events", "none")
.attr("class", "mouse-focus-label-y");
if (this._data) {
this._applyData();
}
return container;
},
_dragHandler: function() {
//we don´t want map events to occur here
d3.event.preventDefault();
d3.event.stopPropagation();
this._gotDragged = true;
this._drawDragRectangle();
},
/*
* Draws the currently dragged rectabgle over the chart.
*/
_drawDragRectangle: function() {
if (!this._dragStartCoords) {
return;
}
var dragEndCoords = this._dragCurrentCoords = d3.mouse(this._background.node());
var x1 = Math.min(this._dragStartCoords[0], dragEndCoords[0]),
x2 = Math.max(this._dragStartCoords[0], dragEndCoords[0]);
if (!this._dragRectangle && !this._dragRectangleG) {
var g = d3.select(this._container).select("svg").select("g");
this._dragRectangleG = g.append("g");
this._dragRectangle = this._dragRectangleG.append("rect")
.attr("width", x2 - x1)
.attr("height", this._height())
.attr("x", x1)
.attr('class', 'mouse-drag')
.style("pointer-events", "none");
} else {
this._dragRectangle.attr("width", x2 - x1)
.attr("x", x1);
}
},
/*
* Removes the drag rectangle and zoms back to the total extent of the data.
*/
_resetDrag: function() {
if (this._dragRectangleG) {
this._dragRectangleG.remove();
this._dragRectangleG = null;
this._dragRectangle = null;
this._hidePositionMarker();
this._map.fitBounds(this._fullExtent);
}
},
/*
* Handles end of dragg operations. Zooms the map to the selected items extent.
*/
_dragEndHandler: function() {
if (!this._dragStartCoords || !this._gotDragged) {
this._dragStartCoords = null;
this._gotDragged = false;
this._resetDrag();
return;
}
this._hidePositionMarker();
var item1 = this._findItemForX(this._dragStartCoords[0]),
item2 = this._findItemForX(this._dragCurrentCoords[0]);
this._fitSection(item1, item2);
this._dragStartCoords = null;
this._gotDragged = false;
},
_dragStartHandler: function() {
d3.event.preventDefault();
d3.event.stopPropagation();
this._gotDragged = false;
this._dragStartCoords = d3.mouse(this._background.node());
},
/*
* Finds a data entry for a given x-coordinate of the diagram
*/
_findItemForX: function(x) {
var bisect = d3.bisector(function(d) {
return d.dist;
}).left;
var xinvert = this._x.invert(x);
return bisect(this._data, xinvert);
},
/** Make the map fit the route section between given indexes. */
_fitSection: function(index1, index2) {
var start = Math.min(index1, index2),
end = Math.max(index1, index2);
var ext = this._calculateFullExtent(this._data.slice(start, end));
this._map.fitBounds(ext);
},
_initToggle: function() {
/* inspired by L.Control.Layers */
var container = this._container;
//Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
container.setAttribute('aria-haspopup', true);
if (!L.Browser.touch) {
L.DomEvent
.disableClickPropagation(container);
//.disableScrollPropagation(container);
} else {
L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
}
if (this.options.collapsed) {
this._collapse();
if (!L.Browser.android) {
L.DomEvent
.on(container, 'mouseover', this._expand, this)
.on(container, 'mouseout', this._collapse, this);
}
var link = this._button = L.DomUtil.create('a', 'elevation-toggle', container);
link.href = '#';
link.title = 'Elevation';
if (L.Browser.touch) {
L.DomEvent
.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', this._expand, this);
} else {
L.DomEvent.on(link, 'focus', this._expand, this);
}
this._map.on('click', this._collapse, this);
// TODO keyboard accessibility
}
},
_expand: function() {
this._container.className = this._container.className.replace(' elevation-collapsed', '');
},
_collapse: function() {
L.DomUtil.addClass(this._container, 'elevation-collapsed');
},
_width: function() {
var opts = this.options;
return opts.width - opts.margins.left - opts.margins.right;
},
_height: function() {
var opts = this.options;
return opts.height - opts.margins.top - opts.margins.bottom;
},
/*
* Fromatting funciton using the given decimals and seperator
*/
_formatter: function(num, dec, sep) {
var res;
if (dec === 0) {
res = Math.round(num) + "";
} else {
res = L.Util.formatNum(num, dec) + "";
}
var numbers = res.split(".");
if (numbers[1]) {
var d = dec - numbers[1].length;
for (; d > 0; d--) {
numbers[1] += "0";
}
res = numbers.join(sep || ".");
}
return res;
},
_appendYaxis: function(y) {
y.attr("class", "y axis")
.call(d3.svg.axis()
.scale(this._y)
.ticks(this.options.yTicks)
.orient("left"))
.append("text")
.attr("x", -45)
.attr("y", 3)
.style("text-anchor", "end")
.text("m");
},
_appendXaxis: function(x) {
x.attr("class", "x axis")
.attr("transform", "translate(0," + this._height() + ")")
.call(d3.svg.axis()
.scale(this._x)
.ticks(this.options.xTicks)
.orient("bottom"))
.append("text")
.attr("x", this._width() + 20)
.attr("y", 15)
.style("text-anchor", "end")
.text("km");
},
_updateAxis: function() {
this._xaxisgraphicnode.selectAll("g").remove();
this._xaxisgraphicnode.selectAll("path").remove();
this._xaxisgraphicnode.selectAll("text").remove();
this._yaxisgraphicnode.selectAll("g").remove();
this._yaxisgraphicnode.selectAll("path").remove();
this._yaxisgraphicnode.selectAll("text").remove();
this._appendXaxis(this._xaxisgraphicnode);
this._appendYaxis(this._yaxisgraphicnode);
},
_mouseoutHandler: function() {
this._hidePositionMarker();
},
/*
* Hides the position-/heigth indication marker drawn onto the map
*/
_hidePositionMarker: function() {
if (this._marker) {
this._map.removeLayer(this._marker);
this._marker = null;
}
if (this._mouseHeightFocus) {
this._mouseHeightFocus.style("visibility", "hidden");
this._mouseHeightFocusLabel.style("visibility", "hidden");
}
if (this._pointG) {
this._pointG.style("visibility", "hidden");
}
this._focusG.style("visibility", "hidden");
},
/*
* Handles the moueseover the chart and displays distance and altitude level
*/
_mousemoveHandler: function(d, i, ctx) {
if (!this._data || this._data.length === 0) {
return;
}
var coords = d3.mouse(this._background.node());
var opts = this.options;
this._focusG.style("visibility", "visible");
this._mousefocus.attr('x1', coords[0])
.attr('y1', 0)
.attr('x2', coords[0])
.attr('y2', this._height())
.classed('hidden', false);
var bisect = d3.bisector(function(d) {
return d.dist;
}).left;
var item = this._data[this._findItemForX(coords[0])],
alt = item.altitude,
dist = item.dist,
ll = item.latlng,
numY = opts.hoverNumber.formatter(alt, opts.hoverNumber.decimalsY),
numX = opts.hoverNumber.formatter(dist, opts.hoverNumber.decimalsX);
this._focuslabelX.attr("x", coords[0])
.text(numY + " m");
this._focuslabelY.attr("y", this._height() - 5)
.attr("x", coords[0])
.text(numX + " km");
var layerpoint = this._map.latLngToLayerPoint(ll);
//if we use a height indicator we create one with SVG
//otherwise we show a marker
if (opts.useHeightIndicator) {
if (!this._mouseHeightFocus) {
var heightG = d3.select(".leaflet-overlay-pane svg")
.append("g");
this._mouseHeightFocus = heightG.append('svg:line')
.attr('class', 'height-focus line')
.attr('x2', '0')
.attr('y2', '0')
.attr('x1', '0')
.attr('y1', '0');
var pointG = this._pointG = heightG.append("g");
pointG.append("svg:circle")
.attr("r", 6)
.attr("cx", 0)
.attr("cy", 0)
.attr("class", "height-focus circle-lower");
this._mouseHeightFocusLabel = heightG.append("svg:text")
.attr("class", "height-focus-label")
.style("pointer-events", "none");
}
var normalizedAlt = this._height() / this._maxElevation * alt;
var normalizedY = layerpoint.y - normalizedAlt;
this._mouseHeightFocus.attr("x1", layerpoint.x)
.attr("x2", layerpoint.x)
.attr("y1", layerpoint.y)
.attr("y2", normalizedY)
.style("visibility", "visible");
this._pointG.attr("transform", "translate(" + layerpoint.x + "," + layerpoint.y + ")")
.style("visibility", "visible");
this._mouseHeightFocusLabel.attr("x", layerpoint.x)
.attr("y", normalizedY)
.text(alt + " m")
.style("visibility", "visible");
} else {
if (!this._marker) {
this._marker = new L.Marker(ll).addTo(this._map);
} else {
this._marker.setLatLng(ll);
}
}
},
/*
* Parsing of GeoJSON data lines and their elevation in z-coordinate
*/
_addGeoJSONData: function(coords) {
if (coords) {
var data = this._data || [];
var dist = this._dist || 0;
var ele = this._maxElevation || 0;
for (var i = 0; i < coords.length; i++) {
var s = new L.LatLng(coords[i][1], coords[i][0]);
var e = new L.LatLng(coords[i ? i - 1 : 0][1], coords[i ? i - 1 : 0][0]);
var newdist = s.distanceTo(e);
dist = dist + Math.round(newdist / 1000 * 100000) / 100000;
ele = ele < coords[i][2] ? coords[i][2] : ele;
data.push({
dist: dist,
altitude: coords[i][2],
x: coords[i][0],
y: coords[i][1],
latlng: s
});
}
this._dist = dist;
this._data = data;
this._maxElevation = ele;
}
},
/*
* Parsing function for GPX data as used by https://github.com/mpetazzoni/leaflet-gpx
*/
_addGPXdata: function(coords) {
if (coords) {
var data = this._data || [];
var dist = this._dist || 0;
var ele = this._maxElevation || 0;
for (var i = 0; i < coords.length; i++) {
var s = coords[i];
var e = coords[i ? i - 1 : 0];
var newdist = s.distanceTo(e);
dist = dist + Math.round(newdist / 1000 * 100000) / 100000;
ele = ele < s.meta.ele ? s.meta.ele : ele;
data.push({
dist: dist,
altitude: s.meta.ele,
x: s.lng,
y: s.lat,
latlng: s
});
}
this._dist = dist;
this._data = data;
this._maxElevation = ele;
}
},
_addData: function(d) {
var geom = d && d.geometry && d.geometry;
var i;
if (geom) {
switch (geom.type) {
case 'LineString':
this._addGeoJSONData(geom.coordinates);
break;
case 'MultiLineString':
for (i = 0; i < geom.coordinates.length; i++) {
this._addGeoJSONData(geom.coordinates[i]);
}
break;
default:
throw new Error('Invalid GeoJSON object.');
}
}
var feat = d && d.type === "FeatureCollection";
if (feat) {
for (i = 0; i < d.features.length; i++) {
this._addData(d.features[i]);
}
}
if (d && d._latlngs) {
this._addGPXdata(d._latlngs);
}
},
/*
* Calculates the full extent of the data array
*/
_calculateFullExtent: function(data) {
if (!data || data.length < 1) {
throw new Error("no data in parameters");
}
var ext = new L.latLngBounds(data[0].latlng, data[0].latlng);
data.forEach(function(item) {
ext.extend(item.latlng);
});
return ext;
},
/*
* Add data to the diagram either from GPX or GeoJSON and
* update the axis domain and data
*/
addData: function(d) {
this._addData(d);
if (this._container) {
this._applyData();
}
},
_applyData: function() {
var xdomain = d3.extent(this._data, function(d) {
return d.dist;
});
var ydomain = d3.extent(this._data, function(d) {
return d.altitude;
});
var opts = this.options;
if (opts.yAxisMin !== undefined && (opts.yAxisMin < ydomain[0] || opts.forceAxisBounds)) {
ydomain[0] = opts.yAxisMin;
}
if (opts.yAxisMax !== undefined && (opts.yAxisMax > ydomain[1] || opts.forceAxisBounds)) {
ydomain[1] = opts.yAxisMax;
}
this._x.domain(xdomain);
this._y.domain(ydomain);
this._areapath.datum(this._data)
.attr("d", this._area);
this._updateAxis();
this._fullExtent = this._calculateFullExtent(this._data);
},
/*
* Reset data
*/
_clearData: function() {
this._data = null;
this._dist = null;
this._maxElevation = null;
},
/*
* Reset data and display
*/
clear: function() {
this._clearData();
if (!this._areapath) {
return;
}
// workaround for 'Error: Problem parsing d=""' in Webkit when empty data
// https://groups.google.com/d/msg/d3-js/7rFxpXKXFhI/HzIO_NPeDuMJ
//this._areapath.datum(this._data).attr("d", this._area);
this._areapath.attr("d", "M0 0");
this._x.domain([0, 1]);
this._y.domain([0, 1]);
this._updateAxis();
}
});
L.control.elevation = function(options) {
return new L.Control.Elevation(options);
};

View file

@ -1,70 +0,0 @@
.@{theme}{
.leaflet-control.elevation .background{
background-color:@background;
.rounded-corners;
}
.leaflet-control.elevation{
.axis path,
.axis line {
fill: none;
stroke: @axis-color;
stroke-width:@stroke-width-axis;
}
}
.leaflet-control.elevation .area {
fill: @base-color;
}
.leaflet-control.elevation .mouse-focus-line {
pointer-events: none;
stroke-width:@stroke-width-mouse-focus;
stroke:@stroke-color;
}
.leaflet-control.elevation .elevation-toggle {
cursor: pointer;
box-shadow: 0 1px 7px rgba(0,0,0,0.4);
-webkit-border-radius: 5px;
border-radius: 5px;
width: 36px;
height: 36px;
background: url('images/elevation.png') no-repeat center center #f8f8f9;
}
.leaflet-control.elevation-collapsed .background {
display: none;
}
.leaflet-control.elevation-collapsed .elevation-toggle {
display: block;
}
.leaflet-control.elevation{
.mouse-focus-label-y,
.mouse-focus-label-x {
}
.mouse-drag{
fill:@drag-color;
}
}
.leaflet-overlay-pane {
.height-focus{
stroke:@base-color;
fill:@base-color;
}
.height-focus.line{
pointer-events: none;
stroke-width:@stroke-width-height-focus;
}
.height-focus-label{
}
.height-focus.circle-lower {
}
}
}

View file

@ -1,20 +0,0 @@
@theme : lime-theme;
@base-color : #9CC222;
@highlight-color : #637E0B;
@background : fade(@base-color,20%);
@drag-color : fade(@highlight-color,40%);
@axis-color : darken(@base-color,20%);
@stroke-color : darken(@base-color,40%);
@stroke-width-mouse-focus : 1;
@stroke-width-height-focus: 2;
@stroke-width-axis : 2;
.rounded-corners (@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
-ms-border-radius: @radius;
-o-border-radius: @radius;
border-radius: @radius;
}
@import "../L.Control.Elevation.less";

View file

@ -1,20 +0,0 @@
@theme : purple-theme;
@base-color : #732C7B;
@highlight-color : #4A0E50;
@background : fade(@base-color,20%);
@drag-color : fade(@highlight-color,40%);
@axis-color : darken(@base-color,20%);
@stroke-color : darken(@base-color,40%);
@stroke-width-mouse-focus : 1;
@stroke-width-height-focus: 2;
@stroke-width-axis : 2;
.rounded-corners (@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
-ms-border-radius: @radius;
-o-border-radius: @radius;
border-radius: @radius;
}
@import "../L.Control.Elevation.less";

View file

@ -1,20 +0,0 @@
@theme : steelblue-theme;
@base-color : #4682B4;
@highlight-color : #174A75;
@background : fade(@base-color,20%);
@drag-color : fade(@highlight-color,40%);
@axis-color : darken(@base-color,40%);
@stroke-color : darken(@base-color,40%);
@stroke-width-mouse-focus : 1;
@stroke-width-height-focus: 2;
@stroke-width-axis : 2;
.rounded-corners (@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
-ms-border-radius: @radius;
-o-border-radius: @radius;
border-radius: @radius;
}
@import "../L.Control.Elevation.less";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 B

View file

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="26"
width="26"
id="svg2"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="elevation.svg"
inkscape:export-filename="/home/z4k/www/maps/Leaflet.Elevation/src/images/elevation.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 13 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="26 : 13 : 1"
inkscape:persp3d-origin="13 : 8.6666667 : 1"
id="perspective22" />
<inkscape:perspective
id="perspective5368"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1336"
inkscape:window-height="716"
id="namedview16"
showgrid="false"
inkscape:zoom="12.836708"
inkscape:cx="9.2793304"
inkscape:cy="10.065073"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" />
<path
sodipodi:nodetypes="ccccccc"
d="M 23.116338,20.847501 18.876285,12.717757 15.034906,12.602581 12.270363,14.369079 9.9164116,8.9203569 4.723308,15.1073 l 0,5.740201"
style="fill:#addb55;fill-opacity:0.83794466000000001;stroke:none;opacity:0.8503937"
id="path4581"
inkscape:export-filename="/home/z4k/www/climbo/images/dis.png"
inkscape:export-xdpi="37.075794"
inkscape:export-ydpi="37.075794" />
<path
id="path4508"
style="fill:none;stroke:#70ab00;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 4.7148336,14.751112 1.0850165,0 4.3152399,-6.1185111 2.522013,5.5932591 2.482614,-2.287207 3.698573,0.128868 4.049243,8.326572 0,0.440076"
sodipodi:nodetypes="cccccccc"
inkscape:export-filename="/home/z4k/www/climbo/images/dis.png"
inkscape:export-xdpi="37.075794"
inkscape:export-ydpi="37.075794" />
<path
style="fill:none;stroke:#737373;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
d="m 3.4214623,4.9854716 0,19.7870054"
id="path2825" />
<path
style="fill:none;stroke:#737373;stroke-width:1px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1"
d="m 24.68144,22.435429 -23.75282884,0"
id="path2827"
sodipodi:nodetypes="cc" />
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -1,19 +0,0 @@
Copyright (c) 2010-2014 Caolan McMahon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,14 +0,0 @@
{
"name": "leaflet-plugins",
"homepage": "https://github.com/shramov/leaflet-plugins",
"version": "1.1.2",
"_release": "1.1.2",
"_resolution": {
"type": "version",
"tag": "v1.1.2",
"commit": "de2380a9efa24b3b43fb780219363f171f9f3140"
},
"_source": "git://github.com/shramov/leaflet-plugins.git",
"_target": "*",
"_originalSource": "leaflet-plugins"
}

View file

@ -1,11 +0,0 @@
{
"browser": true,
"eqeqeq": true,
"undef": true,
"quotmark": "single",
"trailing": true,
"laxbreak": true,
"globals": {
"L": true
}
}

View file

@ -1,22 +0,0 @@
Copyright (c) 2011-2014, Pavel Shramov, Bruno Bergot
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,41 +0,0 @@
Leaflet plugins
===============
== What's it?
Miscellaneous plugins for Leaflet library for services that need to display
route information and need satellite imagery from different providers.
Currently it consists of:
- Vector layers (`layer/vector/`):
* GPX
* KML
- Providers (`layer/tile`):
* Google - using Google Maps API v3;
* Yandex - using Yandex Maps API v2;
* Bing - with proper attribution.
All these providers are implemented with respect to terms of use.
Also there are some useful control plugins (`control/`):
* Permalink - OpenLayers compatible permanent link with support for storing
location data in hash part (#lat=...);
* Distance - simple tool to measure distances on maps
== How to get?
http://psha.org.ru/cgit/psha/leaflet-plugins.git
or
http://github.com/shramov/leaflet-plugins.git
== Russian docs
See link:http://psha.org.ru/b/leaflet-plugins.ru.html[russian documentation] for more info.
////////////////////////////////////
vim: sts=4 sw=4 et tw=80 ft=asciidoc
////////////////////////////////////

View file

@ -1,28 +0,0 @@
JS := $(wildcard ../layer/*/*.js ../layer/*.js ../control/*js)
#JS += control/Scale.js control/Distance.js
#JS += control/Permalink.js $(wildcard control/Permalink.*.js)
JS := $(shell python ./deps.py $(JS))
#JS_EXTRA := $(JS) $(wildcard layer/*.js)
all: compiled.yui.js compiled.closure.js
compile: $(patsubst %,compiled/%,$(JS))
closure/%: ../%
mkdir -p $(dir $@)
java -jar /tmp/closure.jar --compilation_level ADVANCED_OPTIMIZATIONS --charset UTF-8 --js $< --js_output_file $@.tmp
mv $@.tmp $@
yui/%: ../%
mkdir -p $(dir $@)
yui-compressor --charset UTF-8 -o $@.tmp $<
mv $@.tmp $@
compiled.yui.js: $(patsubst ../%,yui/%,$(JS))
compiled.closure.js: $(patsubst ../%,closure/%,$(JS))
compiled.%.js:
for f in $^; do cat $$f >> $@.tmp; echo >> $@.tmp; done
mv $@.tmp $@
.PHONY: all compile

View file

@ -1,26 +0,0 @@
#!/usr/bin/env python
# vim: sts=4 sw=4 et
import os, sys
printed = set()
def includes(f):
d = os.path.dirname(f)
for l in open(f):
if l.startswith('//#include'):
yield os.path.join(d, l.strip().split(None, 1)[1].strip(""""'"""))
work = list(sys.argv[1:])
while work:
f = work.pop(0)
if f in printed:
continue
i = list(filter(lambda x: x not in printed, includes(f)))
if i:
work = i + [f] + work
continue
printed.add(f)
print f

View file

@ -1,128 +0,0 @@
/* global console: true */
L.Control.Distance = L.Control.extend({
options: {
position: 'topleft',
popups: true
},
initialize: function (options) {
L.Util.setOptions(this, options);
this._line = new L.Polyline([], {editable: true});
this._line.on('edit', this._update, this);
this._line.on('click', function(e) {});
this._active = false;
},
getLine: function() { return this._line; },
onAdd: function(map) {
var className = 'leaflet-control-distance',
container = this._container = L.DomUtil.create('div', className);
function cb() {
if (this._active)
this._calc_disable();
else
this._calc_enable();
}
var link = this._link = this._createButton('Edit', 'leaflet-control-distance leaflet-control-distance-edit', container, cb, this);
var del = this._link_delete = this._createButton('Delete', 'leaflet-control-distance leaflet-control-distance-delete', container, this._reset, this);
var text = this._text = L.DomUtil.create('div', 'leaflet-control-distance-text', container);
//text.style.display = 'inline';
//text.style.float = 'right';
this._map.addLayer(this._line);
this._calc_disable();
return container;
},
_createButton: function (title, className, container, fn, context) {
var link = L.DomUtil.create('a', className, container);
link.href = '#';
link.title = title;
L.DomEvent
.addListener(link, 'click', L.DomEvent.stopPropagation)
.addListener(link, 'click', L.DomEvent.preventDefault)
.addListener(link, 'click', fn, context);
return link;
},
onRemove: function(map) {
this._calc_disable();
},
_calc_enable: function() {
this._map.on('click', this._add_point, this);
this._map.getContainer().style.cursor = 'crosshair';
//this._map.addLayer(this._line);
L.DomUtil.addClass(this._link, 'leaflet-control-distance-active');
this._container.appendChild(this._link_delete);
this._container.appendChild(this._text);
this._active = true;
this._line.editing.enable();
if (!this._map.hasLayer(this._line))
this._map.addLayer(this._line);
this._update();
},
_calc_disable: function() {
this._map.off('click', this._add_point, this);
//this._map.removeLayer(this._line);
this._map.getContainer().style.cursor = 'default';
this._container.removeChild(this._link_delete);
this._container.removeChild(this._text);
L.DomUtil.removeClass(this._link, 'leaflet-control-distance-active');
this._active = false;
this._line.editing.disable();
},
_add_point: function (e) {
var len = this._line.getLatLngs().length;
this._line.addLatLng(e.latlng);
this._line.editing.updateMarkers();
this._line.fire('edit', {});
},
_reset: function(e) {
this._line.setLatLngs([]);
this._line.fire('edit', {});
this._line.redraw();
this._line.editing.updateMarkers();
},
_update: function(e) {
console.info('Update');
this._text.textContent = this._d2txt(this._distance_calc());
},
_d2txt: function(d) {
if (d < 2000)
return d.toFixed(0) + ' m';
else
return (d/1000).toFixed(1) + ' km';
},
_distance_calc: function(e) {
var ll = this._line.getLatLngs();
var d = 0, p = null;
for (var i = 0; i < ll.length; i++) {
if (i)
d += p.distanceTo(ll[i]);
if (this.options.popups) {
var m = this._line.editing._markers[i];
if (m) {
m.bindPopup(this._d2txt(d));
m.on('mouseover', m.openPopup, m);
m.on('mouseout', m.closePopup, m);
}
}
p = ll[i];
}
return d;
}
});

View file

@ -1,60 +0,0 @@
/*
* Add async initialization of layers to L.Control.Layers
*/
L.Control.Layers.include({
_loadScripts: function(scripts, cb, args) {
if (!scripts || scripts.length === 0)
return cb(args);
var _this = this, s = scripts.pop(), c;
c = L.Control.Layers._script_cache[s];
if (c === undefined) {
c = {url: s, wait: []};
//console.info("Load " + s);
var script = document.createElement('script');
script.src = s;
script.type = 'text/javascript';
script.onload = function () {
var i = 0;
for (i = 0; i < c.wait.length; i++)
c.wait[i]();
};
c.e = script;
document.getElementsByTagName('head')[0].appendChild(script);
}
function _cb() { _this._loadScripts(scripts, cb, args); }
c.wait.push(_cb);
if (c.e.readyState === 'completed')
_cb();
L.Control.Layers._script_cache[s] = c;
},
addLayerDef: function(name, def) {
if (this._layer_defs === undefined)
this._layer_defs = {};
this._layer_defs[name] = def;
},
addLayerDefs: function(defs) {
if (this._layer_defs === undefined)
this._layer_defs = {};
L.Util.extend(this._layer_defs, defs);
},
loadLayer: function(name, deflt) {
var _this = this, l = this._layer_defs[name];
l['default'] = deflt;
this._loadScripts(l.js.reverse(), function(l) {_this._loadLayer(l);}, l);
},
_loadLayer: function(l) {
var x = l.init();
if (l['default'] && this._map)
this._map.addLayer(x);
if (!l.overlay)
this.addBaseLayer(x, l.name);
else
this.addOverlay(x, l.name);
}
});
L.Control.Layers._script_cache = {};

View file

@ -1,76 +0,0 @@
//#include "Permalink.js
L.Control.Permalink.include({
/*
options: {
useMarker: true,
markerOptions: {}
},
*/
initialize_layer: function() {
//console.info("Initialize layer");
this.on('update', this._set_layer, this);
this.on('add', this._onadd_layer, this);
},
_onadd_layer: function(e) {
//console.info("onAdd::layer", e);
this._map.on('layeradd', this._update_layer, this);
this._map.on('layerremove', this._update_layer, this);
this._update_layer();
},
_update_layer: function() {
if (!this.options.layers) return;
//console.info(this.options.layers);
var layer = this.options.layers.currentBaseLayer();
if (layer)
this._update({layer: layer.name});
},
_set_layer: function(e) {
//console.info("Set layer", e);
var p = e.params;
if (!this.options.layers || !p.layer) return;
this.options.layers.chooseBaseLayer(p.layer);
}
});
L.Control.Layers.include({
chooseBaseLayer: function(name) {
var layer, obj;
for (var i in this._layers) {
if (!this._layers.hasOwnProperty(i))
continue;
obj = this._layers[i];
if (!obj.overlay && obj.name === name)
layer = obj.layer;
}
if (!layer || this._map.hasLayer(layer))
return;
for (var j in this._layers) {
if (!this._layers.hasOwnProperty(j))
continue;
obj = this._layers[j];
if (!obj.overlay && this._map.hasLayer(obj.layer))
this._map.removeLayer(obj.layer);
}
this._map.addLayer(layer);
this._update();
},
currentBaseLayer: function() {
for (var i in this._layers) {
if (!this._layers.hasOwnProperty(i))
continue;
var obj = this._layers[i];
//console.info("Layer: ", obj.name, obj);
if (obj.overlay) continue;
if (!obj.overlay && this._map.hasLayer(obj.layer))
return obj;
}
}
});

View file

@ -1,49 +0,0 @@
//#include "Permalink.js
L.Control.Permalink.include({
/*
options: {
line: null
},
*/
initialize_line: function() {
this.on('update', this._set_line, this);
this.on('add', this._onadd_line, this);
},
_onadd_line: function(e) {
//console.info("onAdd::line", e);
if (!this.options.line) return;
this.options.line.on('edit', this._update_line, this);
this._update_line();
},
_update_line: function() {
if (!this.options.line) return;
var line = this.options.line;
if (!line) return;
var text = [], coords = line.getLatLngs();
if (!coords.length)
return this._update({line: null});
for (var i in coords)
text.push(coords[i].lat.toFixed(4) + ',' + coords[i].lng.toFixed(4));
this._update({line: text.join(';')});
},
_set_line: function(e) {
//console.info("Set line", e.params.line);
var p = e.params, l = this.options.line;
if (!l || !p.line) return;
var coords = [], text = p.line.split(';');
for (var i in text) {
var ll = text[i].split(',');
if (ll.length !== 2) continue;
coords.push(new L.LatLng(ll[0], ll[1]));
}
if (!coords.length) return;
l.setLatLngs(coords);
if (!this._map.hasLayer(l))
this._map.addLayer(l);
}
});

View file

@ -1,31 +0,0 @@
//#include "Permalink.js
L.Control.Permalink.include({
/*
options: {
useMarker: true,
markerOptions: {}
},
*/
initialize_marker: function() {
//console.info("Initialize marker");
this.on('update', this._set_marker, this);
},
_set_marker: function(e) {
//console.info("Set marker", e);
var p = e.params;
//if (!this.options.useMarker) return;
if (this._marker) return;
if (p.marker !== 1) return;
if (p.mlat !== undefined && p.mlon !== undefined)
return this._update({mlat: null, mlon: null,
lat: p.mlat, lon: p.mlon, marker: 1});
this._marker = new L.Marker(new L.LatLng(p.lat, p.lon),
this.options.markerOptions);
this._marker.bindPopup('<a href="' + this._update_href() + '">' + this.options.text + '</a>');
this._map.addLayer(this._marker);
this._update({marker: null});
}
});

View file

@ -1,163 +0,0 @@
L.Control.Permalink = L.Control.extend({
includes: L.Mixin.Events,
options: {
position: 'bottomleft',
useAnchor: true,
useLocation: false,
text: 'Permalink'
},
initialize: function(options) {
L.Util.setOptions(this, options);
this._params = {};
this._set_urlvars();
this.on('update', this._set_center, this);
for (var i in this) {
if (typeof(i) === 'string' && i.indexOf('initialize_') === 0)
this[i]();
}
},
onAdd: function(map) {
this._container = L.DomUtil.create('div', 'leaflet-control-attribution leaflet-control-permalink');
L.DomEvent.disableClickPropagation(this._container);
this._map = map;
this._href = L.DomUtil.create('a', null, this._container);
this._href.innerHTML = this.options.text;
map.on('moveend', this._update_center, this);
this.fire('update', {params: this._params});
this._update_center();
if (this.options.useAnchor && 'onhashchange' in window) {
var _this = this, fn = window.onhashchange;
window.onhashchange = function() {
_this._set_urlvars();
if (fn) return fn();
};
}
this.fire('add', {map: map});
return this._container;
},
_update_center: function() {
if (!this._map) return;
var center = this._round_point(this._map.getCenter());
this._update({zoom: this._map.getZoom(), lat: center.lat, lon: center.lng});
},
_update_href: function() {
var params = L.Util.getParamString(this._params);
var sep = '?';
if (this.options.useAnchor) sep = '#';
var url = this._url_base + sep + params.slice(1);
if (this._href) this._href.setAttribute('href', url);
if (this.options.useLocation)
location.replace('#' + params.slice(1));
return url;
},
_round_point : function(point) {
var bounds = this._map.getBounds(), size = this._map.getSize();
var ne = bounds.getNorthEast(), sw = bounds.getSouthWest();
var round = function (x, p) {
if (p === 0) return x;
var shift = 1;
while (p < 1 && p > -1) {
x *= 10;
p *= 10;
shift *= 10;
}
return Math.floor(x)/shift;
};
point.lat = round(point.lat, (ne.lat - sw.lat) / size.y);
point.lng = round(point.lng, (ne.lng - sw.lng) / size.x);
return point;
},
_update: function(obj, source) {
//console.info('Update', obj, this._params);
for(var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (obj[i] !== null && obj[i] !== undefined)
this._params[i] = obj[i];
else
delete this._params[i];
}
this._update_href();
},
_set_urlvars: function()
{
this._url_base = window.location.href.split('#')[0].split('?')[0];
var p;
if (this.options.useAnchor)
p = L.UrlUtil.queryParse(L.UrlUtil.hash());
else
p = L.UrlUtil.queryParse(L.UrlUtil.query());
function eq(x, y) {
for(var i in x)
if (x.hasOwnProperty(i) && x[i] !== y[i])
return false;
return true;
}
if (eq(p, this._params) && eq(this._params, p))
return;
this._params = p;
this._update_href();
this.fire('update', {params: this._params});
},
_set_center: function(e)
{
//console.info('Update center', e);
var params = e.params;
if (params.zoom === undefined ||
params.lat === undefined ||
params.lon === undefined) return;
this._map.setView(new L.LatLng(params.lat, params.lon), params.zoom);
}
});
L.UrlUtil = {
queryParse: function(s) {
var p = {};
var sep = '&';
if (s.search('&amp;') !== -1)
sep = '&amp;';
var params = s.split(sep);
for(var i = 0; i < params.length; i++) {
var tmp = params[i].split('=');
if (tmp.length !== 2) continue;
p[tmp[0]] = decodeURI(tmp[1]);
}
return p;
},
query: function() {
var href = window.location.href.split('#')[0], idx = href.indexOf('?');
if (idx < 0)
return '';
return href.slice(idx+1);
},
hash: function() { return window.location.hash.slice(1); },
updateParamString: function (q, obj) {
var p = L.UrlUtil.queryParse(q);
for (var i in obj) {
if (obj.hasOwnProperty(i))
p[i] = obj[i];
}
return L.Util.getParamString(p).slice(1);
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1,48 +0,0 @@
.leaflet-control-distance {
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
border-radius: 7px;
padding: 5px;
background-color: rgba(0, 0, 0, 0.25);
}
.leaflet-control-distance a, .leaflet-control-distance div {
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
padding: 2px;
background-position: 50% 50%;
background-repeat: no-repeat;
background-color: rgba(255, 255, 255, 0.75);
}
.leaflet-control-distance a {
width: 16px;
height: 16px;
display: inline-block;
}
.leaflet-control-distance div {
font: 11px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
color: #333;
height: 16px;
margin-top: 5px;
white-space: nowrap;
}
.leaflet-control-distance-edit {
/* http://openclipart.org/detail/114727/ftview-ruler-by-anonymous */
background-image: url('measure.png');
}
.leaflet-control-distance-delete {
margin-left: 5px;
/* Based on http://openclipart.org/detail/34729/architetto----tasto-8-by-anonymous */
background-image: url('cross.png');
}
a.leaflet-control-distance-active {
background-color: yellow;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

View file

@ -1,97 +0,0 @@
.osb-popup {
font-family: sans-serif;
font-size: small;
max-width: 380px;
overflow: auto;
}
.osb-popup a:link, .osb-popup a:visited {
border-bottom: 1px dotted #C0C0C0;
text-decoration: none;
}
.osb-popup a:link {
color: #990000;
}
.osb-popup a:visited {
color: #500000;
}
.osb-popup a:link:hover, .osb-popup a:visited:hover {
border-bottom: 1px solid #C0C0C0;
color: red;
}
.osb-popup a:link:focus .osb-popup a:visited:focus {
outline: 1px dotted #C0C0C0;
}
.osb-popup a:link:active, .osb-popup a:visited:active {
border-bottom: 1px solid #F0F0F0;
color: red;
outline: 1px solid #C0C0C0;
}
.osb-popup h1 {
color: #176BC1;
font-size: medium;
margin-bottom: 7px;
margin-top: 0;
}
.osb-popup p {
margin-bottom: 0;
margin-top: 5px;
}
.osb-popup p.Comment {
margin-left: 15px;
margin-top: 5px;
}
.osb-popup p.Note {
border-top: 1px solid gray;
font-size: x-small;
margin-top: 7px;
padding-top: 3px;
}
.osb-popup form + p {
border-top: 1px solid gray;
margin-top: 15px;
padding-top: 10px;
}
.osb-popup ul {
border-top: 1px solid gray;
margin: 10px 0 0;
padding: 5px 0 0;
text-align: center;
}
.osb-popup ul li {
display: inline;
margin-left: 12px;
margin-right: 12px;
padding: 0;
}
.osb-popup form {
margin-bottom: 0;
margin-top: 10px;
}
.osb-popup form.osb-comment {
border-top: 1px solid gray;
padding-top: 5px;
}
.osb-popup form div {
margin-left: 15px;
margin-right: 15px;
margin-top: 5px;
}
.osb-popup form div.osb-footer {
margin-bottom: 0;
margin-top: 15px;
text-align: center;
}
.osb-popup span.osb-inputlabel {
display: inline-block;
margin-right: 10px;
min-width: 110px;
}
.osb-popup input[type="text"] {
min-width: 190px;
}
.osb-popup input[type="button"] {
margin-left: 3px;
margin-right: 3px;
min-width: 75px;
}

View file

@ -1,915 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>KML Samples</name>
<open>1</open>
<description>Unleash your creativity with the help of these examples!</description>
<Style id="downArrowIcon">
<IconStyle>
<Icon>
<href>http://maps.google.com/mapfiles/kml/pal4/icon28.png</href>
</Icon>
</IconStyle>
</Style>
<Style id="globeIcon">
<IconStyle>
<Icon>
<href>http://maps.google.com/mapfiles/kml/pal3/icon19.png</href>
</Icon>
</IconStyle>
<LineStyle>
<width>2</width>
</LineStyle>
</Style>
<Style id="transPurpleLineGreenPoly">
<LineStyle>
<color>7fff00ff</color>
<width>4</width>
</LineStyle>
<PolyStyle>
<color>7f00ff00</color>
</PolyStyle>
</Style>
<Style id="yellowLineGreenPoly">
<LineStyle>
<color>7f00ffff</color>
<width>4</width>
</LineStyle>
<PolyStyle>
<color>7f00ff00</color>
</PolyStyle>
</Style>
<Style id="thickBlackLine">
<LineStyle>
<color>87000000</color>
<width>10</width>
</LineStyle>
</Style>
<Style id="redLineBluePoly">
<LineStyle>
<color>ff0000ff</color>
</LineStyle>
<PolyStyle>
<color>ffff0000</color>
</PolyStyle>
</Style>
<Style id="blueLineRedPoly">
<LineStyle>
<color>ffff0000</color>
</LineStyle>
<PolyStyle>
<color>ff0000ff</color>
</PolyStyle>
</Style>
<Style id="transRedPoly">
<LineStyle>
<width>1.5</width>
</LineStyle>
<PolyStyle>
<color>7d0000ff</color>
</PolyStyle>
</Style>
<Style id="transBluePoly">
<LineStyle>
<width>1.5</width>
</LineStyle>
<PolyStyle>
<color>7dff0000</color>
</PolyStyle>
</Style>
<Style id="transGreenPoly">
<LineStyle>
<width>1.5</width>
</LineStyle>
<PolyStyle>
<color>7d00ff00</color>
</PolyStyle>
</Style>
<Style id="transYellowPoly">
<LineStyle>
<width>1.5</width>
</LineStyle>
<PolyStyle>
<color>7d00ffff</color>
</PolyStyle>
</Style>
<Style id="noDrivingDirections">
<BalloonStyle>
<text><![CDATA[
<b>$[name]</b>
<br /><br />
$[description]
]]></text>
</BalloonStyle>
</Style>
<Folder>
<name>Placemarks</name>
<description>These are just some of the different kinds of placemarks with
which you can mark your favorite places</description>
<LookAt>
<longitude>-122.0839597145766</longitude>
<latitude>37.42222904525232</latitude>
<altitude>0</altitude>
<heading>-148.4122922628044</heading>
<tilt>40.5575073395506</tilt>
<range>500.6566641072245</range>
</LookAt>
<Placemark>
<name>Simple placemark</name>
<description>Attached to the ground. Intelligently places itself at the
height of the underlying terrain.</description>
<Point>
<coordinates>-122.0822035425683,37.42228990140251,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Floating placemark</name>
<visibility>0</visibility>
<description>Floats a defined distance above the ground.</description>
<LookAt>
<longitude>-122.0839597145766</longitude>
<latitude>37.42222904525232</latitude>
<altitude>0</altitude>
<heading>-148.4122922628044</heading>
<tilt>40.5575073395506</tilt>
<range>500.6566641072245</range>
</LookAt>
<styleUrl>#downArrowIcon</styleUrl>
<Point>
<altitudeMode>relativeToGround</altitudeMode>
<coordinates>-122.084075,37.4220033612141,50</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Extruded placemark</name>
<visibility>0</visibility>
<description>Tethered to the ground by a customizable
&quot;tail&quot;</description>
<LookAt>
<longitude>-122.0845787421525</longitude>
<latitude>37.42215078737763</latitude>
<altitude>0</altitude>
<heading>-148.4126684946234</heading>
<tilt>40.55750733918048</tilt>
<range>365.2646606980322</range>
</LookAt>
<styleUrl>#globeIcon</styleUrl>
<Point>
<extrude>1</extrude>
<altitudeMode>relativeToGround</altitudeMode>
<coordinates>-122.0857667006183,37.42156927867553,50</coordinates>
</Point>
</Placemark>
</Folder>
<Folder>
<name>Styles and Markup</name>
<visibility>0</visibility>
<description>With KML it is easy to create rich, descriptive markup to
annotate and enrich your placemarks</description>
<LookAt>
<longitude>-122.0845787422371</longitude>
<latitude>37.42215078726837</latitude>
<altitude>0</altitude>
<heading>-148.4126777488172</heading>
<tilt>40.55750733930874</tilt>
<range>365.2646826292919</range>
</LookAt>
<styleUrl>#noDrivingDirections</styleUrl>
<Document>
<name>Highlighted Icon</name>
<visibility>0</visibility>
<description>Place your mouse over the icon to see it display the new
icon</description>
<LookAt>
<longitude>-122.0856552124024</longitude>
<latitude>37.4224281311035</latitude>
<altitude>0</altitude>
<heading>0</heading>
<tilt>0</tilt>
<range>265.8520424250024</range>
</LookAt>
<Style id="highlightPlacemark">
<IconStyle>
<Icon>
<href>http://maps.google.com/mapfiles/kml/paddle/red-stars.png</href>
</Icon>
</IconStyle>
</Style>
<Style id="normalPlacemark">
<IconStyle>
<Icon>
<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>
</Icon>
</IconStyle>
</Style>
<StyleMap id="exampleStyleMap">
<Pair>
<key>normal</key>
<styleUrl>#normalPlacemark</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#highlightPlacemark</styleUrl>
</Pair>
</StyleMap>
<Placemark>
<name>Roll over this icon</name>
<visibility>0</visibility>
<styleUrl>#exampleStyleMap</styleUrl>
<Point>
<coordinates>-122.0856545755255,37.42243077405461,0</coordinates>
</Point>
</Placemark>
</Document>
<Placemark>
<name>Descriptive HTML</name>
<visibility>0</visibility>
<description><![CDATA[Click on the blue link!<br><br>
Placemark descriptions can be enriched by using many standard HTML tags.<br>
For example:
<hr>
Styles:<br>
<i>Italics</i>,
<b>Bold</b>,
<u>Underlined</u>,
<s>Strike Out</s>,
subscript<sub>subscript</sub>,
superscript<sup>superscript</sup>,
<big>Big</big>,
<small>Small</small>,
<tt>Typewriter</tt>,
<em>Emphasized</em>,
<strong>Strong</strong>,
<code>Code</code>
<hr>
Fonts:<br>
<font color="red">red by name</font>,
<font color="#408010">leaf green by hexadecimal RGB</font>
<br>
<font size=1>size 1</font>,
<font size=2>size 2</font>,
<font size=3>size 3</font>,
<font size=4>size 4</font>,
<font size=5>size 5</font>,
<font size=6>size 6</font>,
<font size=7>size 7</font>
<br>
<font face=times>Times</font>,
<font face=verdana>Verdana</font>,
<font face=arial>Arial</font><br>
<hr>
Links:
<br>
<a href="http://earth.google.com/">Google Earth!</a>
<br>
or: Check out our website at www.google.com
<hr>
Alignment:<br>
<p align=left>left</p>
<p align=center>center</p>
<p align=right>right</p>
<hr>
Ordered Lists:<br>
<ol><li>First</li><li>Second</li><li>Third</li></ol>
<ol type="a"><li>First</li><li>Second</li><li>Third</li></ol>
<ol type="A"><li>First</li><li>Second</li><li>Third</li></ol>
<hr>
Unordered Lists:<br>
<ul><li>A</li><li>B</li><li>C</li></ul>
<ul type="circle"><li>A</li><li>B</li><li>C</li></ul>
<ul type="square"><li>A</li><li>B</li><li>C</li></ul>
<hr>
Definitions:<br>
<dl>
<dt>Google:</dt><dd>The best thing since sliced bread</dd>
</dl>
<hr>
Centered:<br><center>
Time present and time past<br>
Are both perhaps present in time future,<br>
And time future contained in time past.<br>
If all time is eternally present<br>
All time is unredeemable.<br>
</center>
<hr>
Block Quote:
<br>
<blockquote>
We shall not cease from exploration<br>
And the end of all our exploring<br>
Will be to arrive where we started<br>
And know the place for the first time.<br>
<i>-- T.S. Eliot</i>
</blockquote>
<br>
<hr>
Headings:<br>
<h1>Header 1</h1>
<h2>Header 2</h2>
<h3>Header 3</h3>
<h3>Header 4</h4>
<h3>Header 5</h5>
<hr>
Images:<br>
<i>Remote image</i><br>
<img src="//developers.google.com/kml/documentation/images/googleSample.png"><br>
<i>Scaled image</i><br>
<img src="//developers.google.com/kml/documentation/images/googleSample.png" width=100><br>
<hr>
Simple Tables:<br>
<table border="1" padding="1">
<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td></tr>
<tr><td>a</td><td>b</td><td>c</td><td>d</td><td>e</td></tr>
</table>
<br>
[Did you notice that double-clicking on the placemark doesn't cause the viewer to take you anywhere? This is because it is possible to directly author a "placeless placemark". If you look at the code for this example, you will see that it has neither a point coordinate nor a LookAt element.]]]></description>
</Placemark>
</Folder>
<Folder>
<name>Ground Overlays</name>
<visibility>0</visibility>
<description>Examples of ground overlays</description>
<GroundOverlay>
<name>Large-scale overlay on terrain</name>
<visibility>0</visibility>
<description>Overlay shows Mount Etna erupting on July 13th, 2001.</description>
<LookAt>
<longitude>15.02468937557116</longitude>
<latitude>37.67395167941667</latitude>
<altitude>0</altitude>
<heading>-16.5581842842829</heading>
<tilt>58.31228652890705</tilt>
<range>30350.36838438907</range>
</LookAt>
<Icon>
<href>http://developers.google.com/kml/documentation/images/etna.jpg</href>
</Icon>
<LatLonBox>
<north>37.91904192681665</north>
<south>37.46543388598137</south>
<east>15.35832653742206</east>
<west>14.60128369746704</west>
<rotation>-0.1556640799496235</rotation>
</LatLonBox>
</GroundOverlay>
</Folder>
<Folder>
<name>Screen Overlays</name>
<visibility>0</visibility>
<description>Screen overlays have to be authored directly in KML. These
examples illustrate absolute and dynamic positioning in screen space.</description>
<ScreenOverlay>
<name>Simple crosshairs</name>
<visibility>0</visibility>
<description>This screen overlay uses fractional positioning to put the
image in the exact center of the screen</description>
<Icon>
<href>http://developers.google.com/kml/documentation/images/crosshairs.png</href>
</Icon>
<overlayXY x="0.5" y="0.5" xunits="fraction" yunits="fraction"/>
<screenXY x="0.5" y="0.5" xunits="fraction" yunits="fraction"/>
<rotationXY x="0.5" y="0.5" xunits="fraction" yunits="fraction"/>
<size x="0" y="0" xunits="pixels" yunits="pixels"/>
</ScreenOverlay>
<ScreenOverlay>
<name>Absolute Positioning: Top left</name>
<visibility>0</visibility>
<Icon>
<href>http://developers.google.com/kml/documentation/images/top_left.jpg</href>
</Icon>
<overlayXY x="0" y="1" xunits="fraction" yunits="fraction"/>
<screenXY x="0" y="1" xunits="fraction" yunits="fraction"/>
<rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
<size x="0" y="0" xunits="fraction" yunits="fraction"/>
</ScreenOverlay>
<ScreenOverlay>
<name>Absolute Positioning: Top right</name>
<visibility>0</visibility>
<Icon>
<href>http://developers.google.com/kml/documentation/images/top_right.jpg</href>
</Icon>
<overlayXY x="1" y="1" xunits="fraction" yunits="fraction"/>
<screenXY x="1" y="1" xunits="fraction" yunits="fraction"/>
<rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
<size x="0" y="0" xunits="fraction" yunits="fraction"/>
</ScreenOverlay>
<ScreenOverlay>
<name>Absolute Positioning: Bottom left</name>
<visibility>0</visibility>
<Icon>
<href>http://developers.google.com/kml/documentation/images/bottom_left.jpg</href>
</Icon>
<overlayXY x="0" y="-1" xunits="fraction" yunits="fraction"/>
<screenXY x="0" y="0" xunits="fraction" yunits="fraction"/>
<rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
<size x="0" y="0" xunits="fraction" yunits="fraction"/>
</ScreenOverlay>
<ScreenOverlay>
<name>Absolute Positioning: Bottom right</name>
<visibility>0</visibility>
<Icon>
<href>http://developers.google.com/kml/documentation/images/bottom_right.jpg</href>
</Icon>
<overlayXY x="1" y="-1" xunits="fraction" yunits="fraction"/>
<screenXY x="1" y="0" xunits="fraction" yunits="fraction"/>
<rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
<size x="0" y="0" xunits="fraction" yunits="fraction"/>
</ScreenOverlay>
<ScreenOverlay>
<name>Dynamic Positioning: Top of screen</name>
<visibility>0</visibility>
<Icon>
<href>http://developers.google.com/kml/documentation/images/dynamic_screenoverlay.jpg</href>
</Icon>
<overlayXY x="0" y="1" xunits="fraction" yunits="fraction"/>
<screenXY x="0" y="1" xunits="fraction" yunits="fraction"/>
<rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
<size x="1" y="0.2" xunits="fraction" yunits="fraction"/>
</ScreenOverlay>
<ScreenOverlay>
<name>Dynamic Positioning: Right of screen</name>
<visibility>0</visibility>
<Icon>
<href>http://developers.google.com/kml/documentation/images/dynamic_right.jpg</href>
</Icon>
<overlayXY x="1" y="1" xunits="fraction" yunits="fraction"/>
<screenXY x="1" y="1" xunits="fraction" yunits="fraction"/>
<rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
<size x="0" y="1" xunits="fraction" yunits="fraction"/>
</ScreenOverlay>
</Folder>
<Folder>
<name>Paths</name>
<visibility>0</visibility>
<description>Examples of paths. Note that the tessellate tag is by default
set to 0. If you want to create tessellated lines, they must be authored
(or edited) directly in KML.</description>
<Placemark>
<name>Tessellated</name>
<visibility>0</visibility>
<description><![CDATA[If the <tessellate> tag has a value of 1, the line will contour to the underlying terrain]]></description>
<LookAt>
<longitude>-112.0822680013139</longitude>
<latitude>36.09825589333556</latitude>
<altitude>0</altitude>
<heading>103.8120432044965</heading>
<tilt>62.04855796276328</tilt>
<range>2889.145007690472</range>
</LookAt>
<LineString>
<tessellate>1</tessellate>
<coordinates> -112.0814237830345,36.10677870477137,0
-112.0870267752693,36.0905099328766,0 </coordinates>
</LineString>
</Placemark>
<Placemark>
<name>Untessellated</name>
<visibility>0</visibility>
<description><![CDATA[If the <tessellate> tag has a value of 0, the line follow a simple straight-line path from point to point]]></description>
<LookAt>
<longitude>-112.0822680013139</longitude>
<latitude>36.09825589333556</latitude>
<altitude>0</altitude>
<heading>103.8120432044965</heading>
<tilt>62.04855796276328</tilt>
<range>2889.145007690472</range>
</LookAt>
<LineString>
<tessellate>0</tessellate>
<coordinates> -112.080622229595,36.10673460007995,0
-112.085242575315,36.09049598612422,0 </coordinates>
</LineString>
</Placemark>
<Placemark>
<name>Absolute</name>
<visibility>0</visibility>
<description>Transparent purple line</description>
<LookAt>
<longitude>-112.2719329043177</longitude>
<latitude>36.08890633450894</latitude>
<altitude>0</altitude>
<heading>-106.8161545998597</heading>
<tilt>44.60763714063257</tilt>
<range>2569.386744398339</range>
</LookAt>
<styleUrl>#transPurpleLineGreenPoly</styleUrl>
<LineString>
<tessellate>1</tessellate>
<altitudeMode>absolute</altitudeMode>
<coordinates> -112.265654928602,36.09447672602546,2357
-112.2660384528238,36.09342608838671,2357
-112.2668139013453,36.09251058776881,2357
-112.2677826834445,36.09189827357996,2357
-112.2688557510952,36.0913137941187,2357
-112.2694810717219,36.0903677207521,2357
-112.2695268555611,36.08932171487285,2357
-112.2690144567276,36.08850916060472,2357
-112.2681528815339,36.08753813597956,2357
-112.2670588176031,36.08682685262568,2357
-112.2657374587321,36.08646312301303,2357 </coordinates>
</LineString>
</Placemark>
<Placemark>
<name>Absolute Extruded</name>
<visibility>0</visibility>
<description>Transparent green wall with yellow outlines</description>
<LookAt>
<longitude>-112.2643334742529</longitude>
<latitude>36.08563154742419</latitude>
<altitude>0</altitude>
<heading>-125.7518698668815</heading>
<tilt>44.61038665812578</tilt>
<range>4451.842204068102</range>
</LookAt>
<styleUrl>#yellowLineGreenPoly</styleUrl>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>absolute</altitudeMode>
<coordinates> -112.2550785337791,36.07954952145647,2357
-112.2549277039738,36.08117083492122,2357
-112.2552505069063,36.08260761307279,2357
-112.2564540158376,36.08395660588506,2357
-112.2580238976449,36.08511401044813,2357
-112.2595218489022,36.08584355239394,2357
-112.2608216347552,36.08612634548589,2357
-112.262073428656,36.08626019085147,2357
-112.2633204928495,36.08621519860091,2357
-112.2644963846444,36.08627897945274,2357
-112.2656969554589,36.08649599090644,2357 </coordinates>
</LineString>
</Placemark>
<Placemark>
<name>Relative</name>
<visibility>0</visibility>
<description>Black line (10 pixels wide), height tracks terrain</description>
<LookAt>
<longitude>-112.2580438551384</longitude>
<latitude>36.1072674824385</latitude>
<altitude>0</altitude>
<heading>4.947421249553717</heading>
<tilt>44.61324882043339</tilt>
<range>2927.61105910266</range>
</LookAt>
<styleUrl>#thickBlackLine</styleUrl>
<LineString>
<tessellate>1</tessellate>
<altitudeMode>relativeToGround</altitudeMode>
<coordinates> -112.2532845153347,36.09886943729116,645
-112.2540466121145,36.09919570465255,645
-112.254734666947,36.09984998366178,645
-112.255493345654,36.10051310621746,645
-112.2563157098468,36.10108441943419,645
-112.2568033076439,36.10159722088088,645
-112.257494011321,36.10204323542867,645
-112.2584106072308,36.10229131995655,645
-112.2596588987972,36.10240001286358,645
-112.2610581199487,36.10213176873407,645
-112.2626285262793,36.10157011437219,645 </coordinates>
</LineString>
</Placemark>
<Placemark>
<name>Relative Extruded</name>
<visibility>0</visibility>
<description>Opaque blue walls with red outline, height tracks terrain</description>
<LookAt>
<longitude>-112.2683594333433</longitude>
<latitude>36.09884362144909</latitude>
<altitude>0</altitude>
<heading>-72.24271551768405</heading>
<tilt>44.60855445139561</tilt>
<range>2184.193522571467</range>
</LookAt>
<styleUrl>#redLineBluePoly</styleUrl>
<LineString>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>relativeToGround</altitudeMode>
<coordinates> -112.2656634181359,36.09445214722695,630
-112.2652238941097,36.09520916122063,630
-112.2645079986395,36.09580763864907,630
-112.2638827428817,36.09628572284063,630
-112.2635746835406,36.09679275951239,630
-112.2635711822407,36.09740038871899,630
-112.2640296531825,36.09804913435539,630
-112.264327720538,36.09880337400301,630
-112.2642436562271,36.09963644790288,630
-112.2639148687042,36.10055381117246,630
-112.2626894973474,36.10149062823369,630 </coordinates>
</LineString>
</Placemark>
</Folder>
<Folder>
<name>Polygons</name>
<visibility>0</visibility>
<description>Examples of polygon shapes</description>
<Folder>
<name>Google Campus</name>
<visibility>0</visibility>
<description>A collection showing how easy it is to create 3-dimensional
buildings</description>
<LookAt>
<longitude>-122.084120030116</longitude>
<latitude>37.42174011925477</latitude>
<altitude>0</altitude>
<heading>-34.82469740081282</heading>
<tilt>53.454348562403</tilt>
<range>276.7870053764046</range>
</LookAt>
<Placemark>
<name>Building 40</name>
<visibility>0</visibility>
<styleUrl>#transRedPoly</styleUrl>
<Polygon>
<extrude>1</extrude>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -122.0848938459612,37.42257124044786,17
-122.0849580979198,37.42211922626856,17
-122.0847469573047,37.42207183952619,17
-122.0845725380962,37.42209006729676,17
-122.0845954886723,37.42215932700895,17
-122.0838521118269,37.42227278564371,17
-122.083792243335,37.42203539112084,17
-122.0835076656616,37.42209006957106,17
-122.0834709464152,37.42200987395161,17
-122.0831221085748,37.4221046494946,17
-122.0829247374572,37.42226503990386,17
-122.0829339169385,37.42231242843094,17
-122.0833837359737,37.42225046087618,17
-122.0833607854248,37.42234159228745,17
-122.0834204551642,37.42237075460644,17
-122.083659133885,37.42251292011001,17
-122.0839758438952,37.42265873093781,17
-122.0842374743331,37.42265143972521,17
-122.0845036949503,37.4226514386435,17
-122.0848020460801,37.42261133916315,17
-122.0847882750515,37.42256395055121,17
-122.0848938459612,37.42257124044786,17 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
<Placemark>
<name>Building 41</name>
<visibility>0</visibility>
<styleUrl>#transBluePoly</styleUrl>
<Polygon>
<extrude>1</extrude>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -122.0857412771483,37.42227033155257,17
-122.0858169768481,37.42231408832346,17
-122.085852582875,37.42230337469744,17
-122.0858799945639,37.42225686138789,17
-122.0858860101409,37.4222311076138,17
-122.0858069157288,37.42220250173855,17
-122.0858379542653,37.42214027058678,17
-122.0856732640519,37.42208690214408,17
-122.0856022926407,37.42214885429042,17
-122.0855902778436,37.422128290487,17
-122.0855841672237,37.42208171967246,17
-122.0854852065741,37.42210455874995,17
-122.0855067264352,37.42214267949824,17
-122.0854430712915,37.42212783846172,17
-122.0850990714904,37.42251282407603,17
-122.0856769818632,37.42281815323651,17
-122.0860162273783,37.42244918858722,17
-122.0857260327004,37.42229239604253,17
-122.0857412771483,37.42227033155257,17 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
<Placemark>
<name>Building 42</name>
<visibility>0</visibility>
<styleUrl>#transGreenPoly</styleUrl>
<Polygon>
<extrude>1</extrude>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -122.0857862287242,37.42136208886969,25
-122.0857312990603,37.42136935989481,25
-122.0857312992918,37.42140934910903,25
-122.0856077073679,37.42138390166565,25
-122.0855802426516,37.42137299550869,25
-122.0852186221971,37.42137299504316,25
-122.0852277765639,37.42161656508265,25
-122.0852598189347,37.42160565894403,25
-122.0852598185499,37.42168200156,25
-122.0852369311478,37.42170017860346,25
-122.0852643957828,37.42176197982575,25
-122.0853239032746,37.42176198013907,25
-122.0853559454324,37.421852864452,25
-122.0854108752463,37.42188921823734,25
-122.0854795379357,37.42189285337048,25
-122.0855436229819,37.42188921797546,25
-122.0856260178042,37.42186013499926,25
-122.085937287963,37.42186013453605,25
-122.0859428718666,37.42160898590042,25
-122.0859655469861,37.42157992759144,25
-122.0858640462341,37.42147115002957,25
-122.0858548911215,37.42140571326184,25
-122.0858091162768,37.4214057134039,25
-122.0857862287242,37.42136208886969,25 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
<Placemark>
<name>Building 43</name>
<visibility>0</visibility>
<styleUrl>#transYellowPoly</styleUrl>
<Polygon>
<extrude>1</extrude>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -122.0844371128284,37.42177253003091,19
-122.0845118855746,37.42191111542896,19
-122.0850470999805,37.42178755121535,19
-122.0850719913391,37.42143663023161,19
-122.084916406232,37.42137237822116,19
-122.0842193868167,37.42137237801626,19
-122.08421938659,37.42147617161496,19
-122.0838086419991,37.4214613409357,19
-122.0837899728564,37.42131306410796,19
-122.0832796534698,37.42129328840593,19
-122.0832609819207,37.42139213944298,19
-122.0829373621737,37.42137236399876,19
-122.0829062425667,37.42151569778871,19
-122.0828502269665,37.42176282576465,19
-122.0829435788635,37.42176776969635,19
-122.083217411188,37.42179248552686,19
-122.0835970430103,37.4217480074456,19
-122.0839455556771,37.42169364237603,19
-122.0840077894637,37.42176283815853,19
-122.084113587521,37.42174801104392,19
-122.0840762473784,37.42171341292375,19
-122.0841447047739,37.42167881534569,19
-122.084144704223,37.42181720660197,19
-122.0842503333074,37.4218170700446,19
-122.0844371128284,37.42177253003091,19 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Folder>
<Folder>
<name>Extruded Polygon</name>
<description>A simple way to model a building</description>
<Placemark>
<name>The Pentagon</name>
<LookAt>
<longitude>-77.05580139178142</longitude>
<latitude>38.870832443487</latitude>
<heading>59.88865561738225</heading>
<tilt>48.09646074797388</tilt>
<range>742.0552506670548</range>
</LookAt>
<Polygon>
<extrude>1</extrude>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -77.05788457660967,38.87253259892824,100
-77.05465973756702,38.87291016281703,100
-77.05315536854791,38.87053267794386,100
-77.05552622493516,38.868757801256,100
-77.05844056290393,38.86996206506943,100
-77.05788457660967,38.87253259892824,100 </coordinates>
</LinearRing>
</outerBoundaryIs>
<innerBoundaryIs>
<LinearRing>
<coordinates> -77.05668055019126,38.87154239798456,100
-77.05542625960818,38.87167890344077,100
-77.05485125901024,38.87076535397792,100
-77.05577677433152,38.87008686581446,100
-77.05691162017543,38.87054446963351,100
-77.05668055019126,38.87154239798456,100 </coordinates>
</LinearRing>
</innerBoundaryIs>
</Polygon>
</Placemark>
</Folder>
<Folder>
<name>Absolute and Relative</name>
<visibility>0</visibility>
<description>Four structures whose roofs meet exactly. Turn on/off
terrain to see the difference between relative and absolute
positioning.</description>
<LookAt>
<longitude>-112.3348969157552</longitude>
<latitude>36.14845533214919</latitude>
<altitude>0</altitude>
<heading>-86.91235037566909</heading>
<tilt>49.30695423894192</tilt>
<range>990.6761201087104</range>
</LookAt>
<Placemark>
<name>Absolute</name>
<visibility>0</visibility>
<styleUrl>#transBluePoly</styleUrl>
<Polygon>
<tessellate>1</tessellate>
<altitudeMode>absolute</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -112.3372510731295,36.14888505105317,1784
-112.3356128688403,36.14781540589019,1784
-112.3368169371048,36.14658677734382,1784
-112.3384408457543,36.14762778914076,1784
-112.3372510731295,36.14888505105317,1784 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
<Placemark>
<name>Absolute Extruded</name>
<visibility>0</visibility>
<styleUrl>#transRedPoly</styleUrl>
<Polygon>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>absolute</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -112.3396586818843,36.14637618647505,1784
-112.3380597654315,36.14531751871353,1784
-112.3368254237788,36.14659596244607,1784
-112.3384555043203,36.14762621763982,1784
-112.3396586818843,36.14637618647505,1784 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
<Placemark>
<name>Relative</name>
<visibility>0</visibility>
<LookAt>
<longitude>-112.3350152490417</longitude>
<latitude>36.14943123077423</latitude>
<altitude>0</altitude>
<heading>-118.9214100848499</heading>
<tilt>37.92486261093203</tilt>
<range>345.5169113679813</range>
</LookAt>
<styleUrl>#transGreenPoly</styleUrl>
<Polygon>
<tessellate>1</tessellate>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -112.3349463145932,36.14988705767721,100
-112.3354019540677,36.14941108398372,100
-112.3344428289146,36.14878490381308,100
-112.3331289492913,36.14780840132443,100
-112.3317019516947,36.14680755678357,100
-112.331131440106,36.1474173426228,100
-112.332616324338,36.14845453364654,100
-112.3339876620524,36.14926570522069,100
-112.3349463145932,36.14988705767721,100 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
<Placemark>
<name>Relative Extruded</name>
<visibility>0</visibility>
<LookAt>
<longitude>-112.3351587892382</longitude>
<latitude>36.14979247129029</latitude>
<altitude>0</altitude>
<heading>-55.42811560891606</heading>
<tilt>56.10280503739589</tilt>
<range>401.0997279712519</range>
</LookAt>
<styleUrl>#transYellowPoly</styleUrl>
<Polygon>
<extrude>1</extrude>
<tessellate>1</tessellate>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates> -112.3348783983763,36.1514008468736,100
-112.3372535345629,36.14888517553886,100
-112.3356068927954,36.14781612679284,100
-112.3350034807972,36.14846469024177,100
-112.3358353861232,36.1489624162954,100
-112.3345888301373,36.15026229372507,100
-112.3337937856278,36.14978096026463,100
-112.3331798208424,36.1504472788618,100
-112.3348783983763,36.1514008468736,100 </coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Folder>
</Folder>
</Document>
</kml>

View file

@ -1,19 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/tile/Bing.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(67.6755, 33.936), zoom: 10 });
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var bing = new L.BingLayer("Anqm0F_JjIZvT0P3abS6KONpaBaKuTnITRrnYuiJCE0WOhH6ZbE4DzeT6brvKVR5");
map.addLayer(bing);
map.addControl(new L.Control.Layers({'OSM':osm, "Bing":bing}, {}));
</script>
</body>
</html>

View file

@ -1,54 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<!--<script src="http://api-maps.yandex.ru/2.0/?load=package.map&lang=ru-RU" type="text/javascript"></script>-->
<script src="../layer/Layer.Deferred.js"></script>
<!--<script src="../layer/tile/Yandex.js"></script>-->
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(67.6755, 33.936), zoom: 10, zoomAnimation: false });
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
var layerdefs = {
mapnik: { name: "Mapnik", js: [],
init: function() {return new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');}},
kosmo: { name: "Космоснимки", js: [],
init: function() {return new L.TileLayer('http://{s}.tile.osmosnimki.ru/kosmo/{z}/{x}/{y}.png', {attribution:'Tiles Courtesy of <a href="http://kosmosnimki.ru/" target="_blank">kosmosnimki.ru</a>'});}},
gsat: { name: "Google", js: ["../layer/tile/Google.js", "http://maps.google.com/maps/api/js?v=3&sensor=false&callback=L.Google.asyncInitialize"],
init: function() {return new L.Google(); }},
ysat: { name: "Yandex", js: ["../layer/tile/Yandex.js", "http://api-maps.yandex.ru/2.0/?load=package.map&lang=ru-RU"],
init: function() {return new L.Yandex("satellite"); }},
nyak: { name: "НЯК", js: ["../layer/tile/Yandex.js", "http://api-maps.yandex.ru/2.0/?load=package.map&lang=ru-RU"],
init: function() {return new L.Yandex("publicMap"); }},
traffic: { name: "Пробки", js: ["../layer/tile/Yandex.js", "http://api-maps.yandex.ru/2.0/?load=package.map&lang=ru-RU"],
init: function() {return new L.Yandex("null", {traffic: true, opacity: 0.8, overlay: true}); }, overlay: true},
mso: { name: "Mapsurfer", js: [], overlay: true,
init: function() {return new L.TileLayer('http://129.206.74.245:8003/tms_h.ashx?x={x}&y={y}&z={z}');}}
};
var yndx = new L.DeferredLayer(layerdefs.ysat);
var kosmo = new L.DeferredLayer(layerdefs.kosmo);
var google = new L.DeferredLayer(layerdefs.gsat);
var ytraffic = new L.DeferredLayer(layerdefs.traffic);
var mso = new L.DeferredLayer(layerdefs.mso);
L.control.layers(
{
'OSM':osm,
"Kosmo":kosmo,
"Google":google,
"Yandex":yndx
},{
"Пробки":ytraffic,
"OpenMapSurfer":mso
}
).addTo(map);
</script>
</body>
</html>

View file

@ -1,36 +0,0 @@
<html>
<!--
vim: sts=4 sw=4 et
-->
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<link rel="stylesheet" href="../css/distance.css" />
<link rel="stylesheet" href="http://leaflet.github.io/Leaflet.draw/leaflet.draw.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="http://leaflet.github.io/Leaflet.draw/leaflet.draw.js"></script>
<script src="../layer/vector/GPX.js"></script>
<script src="../control/Scale.js"></script>
<script src="../control/Permalink.js"></script>
<script src="../control/Permalink.Line.js"></script>
<script src="../control/Distance.js"></script>
</head>
</head>
<body>
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
</script>
<script type="text/javascript">
var map = new L.Map('map', {center: new L.LatLng(58.4, 43.0), zoom: 11});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
map.addLayer(osm);
var d = new L.Control.Distance(); map.addControl(d);
map.addControl(new L.Control.Scale());
map.addControl(new L.Control.Permalink({line: d.getLine(), useLocation: true}));
</script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -1,33 +0,0 @@
<html>
<head>
<title>Google Custom Styles // Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="http://maps.google.com/maps/api/js?v=3&sensor=false"></script>
<script src="../layer/tile/Google.js"></script>
</head>
<body>
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(53.9618, 58.4277), zoom: 13});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var styles = [
{
featureType: 'all',
stylers: [{hue: '#ff0000'}]
}
];
var ggl = new L.Google('ROADMAP', {
mapOptions: {
styles: styles
}
});
map.addLayer(ggl);
map.addControl(new L.Control.Layers( {'OSM':osm, 'Google':ggl}, {}));
</script>
</body>
</html>

View file

@ -1,22 +0,0 @@
<html>
<head>
<title>Google // Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="http://maps.google.com/maps/api/js?v=3&sensor=false"></script>
<script src="../layer/tile/Google.js"></script>
</head>
<body>
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(53.9618, 58.4277), zoom: 13});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var ggl = new L.Google();
var ggl2 = new L.Google('TERRAIN');
map.addLayer(ggl);
map.addControl(new L.Control.Layers( {'OSM':osm, 'Google':ggl, 'Google Terrain':ggl2}, {}));
</script>
</body>
</html>

View file

@ -1,24 +0,0 @@
<html>
<head>
<title>Leaflet - GPX track without Waypoints</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/vector/GPX.js"></script>
</head>
<body>
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(58.4, 43.0), zoom: 11});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var track = new L.GPX("fells_loop.gpx", {async: true, display_wpt:false})
.on("loaded", function(e) { map.fitBounds(e.target.getBounds()); });
map.addLayer(track);
map.addLayer(osm);
map.addControl(new L.Control.Layers({}, {'GPX':track}));
</script>
</body>
</html>

View file

@ -1,26 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/vector/GPX.js"></script>
<script src="../layer/vector/GPX.Speed.js"></script>
</head>
<body>
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(58.4, 43.0), zoom: 11});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var track = new L.GPX("speed.gpx", {async: true})
.on("loaded", function(e) { map.fitBounds(e.target.getBounds()); })
.speedSplitEnable({maxSpeed: 100, chunks: 1000});
map.addLayer(track);
map.addLayer(osm);
map.addControl(new L.Control.Layers({}, {'GPX':track}));
</script>
</body>
</html>

View file

@ -1,24 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/vector/GPX.js"></script>
</head>
<body>
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(58.4, 43.0), zoom: 11});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var track = new L.GPX("fells_loop.gpx", {async: true})
.on("loaded", function(e) { map.fitBounds(e.target.getBounds()); });
map.addLayer(track);
map.addLayer(osm);
map.addControl(new L.Control.Layers({}, {'GPX':track}));
</script>
</body>
</html>

View file

@ -1,24 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/vector/KML.js"></script>
</head>
<body>
<!-- define a DIV into which the map will appear. Make it take up the whole window -->
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(58.4, 43.0), zoom: 11});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var track = new L.KML("KML_Samples.kml", {async: true});
track.on("loaded", function(e) { map.fitBounds(e.target.getBounds()); });
map.addLayer(track);
map.addLayer(osm);
map.addControl(new L.Control.Layers({}, {'Track':track}));
</script>
</body>
</html>

View file

@ -1,39 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/Icon.Canvas.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(67.66904, 33.68595), zoom: 10});
map.addLayer(new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'));
var circle = new L.Icon.Canvas({iconSize: new L.Point(30, 30)});
circle.draw = function(ctx, w, h) {
ctx.translate(w/2, h/2);
ctx.beginPath();
ctx.fillStyle = "#F00";
ctx.arc(0, 0, w/2-1, 0, Math.PI*2, true);
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = '#FFF';
ctx.moveTo(-w/5, -h/5);
ctx.lineTo(w/5, h/5);
ctx.moveTo(-w/5, h/5);
ctx.lineTo(w/5, -h/5);
ctx.stroke();
ctx.closePath();
}
map.addLayer(new L.Marker(map.getCenter(), {icon: circle, draggable: true, opacity: 0.7}));
</script>
</body>
</html>

View file

@ -1,27 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/Marker.Rotate.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(67.6755, 33.936), zoom: 10});
map.addLayer(new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'));
var marker = new L.Marker(map.getCenter(), {iconAngle: 90});
map.addLayer(marker);
var angle = 0;
function _rotate() {
marker.setIconAngle(angle);
angle = (angle + 10) % 360;
setTimeout(_rotate, 1000);
}
_rotate();
</script>
</body>
</html>

View file

@ -1,21 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/Marker.Text.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(67.66904, 33.68595), zoom: 10});
map.addLayer(new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'));
var marker = new L.Marker.Text(map.getCenter(), 'Sweet!');
map.addLayer(new L.Marker(map.getCenter(), {opacity: 0.5}));
map.addLayer(marker);
</script>
</body>
</html>

View file

@ -1,24 +0,0 @@
<html>
<!--
vim: sts=4 sw=4 et
-->
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<link rel="stylesheet" href="../css/osb.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/OpenStreetBugs.js"></script>
</head>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type="text/javascript">
var map = new L.Map('map', {center: new L.LatLng(57.62, 39.89), zoom: 11});
map.addLayer(new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'));
map.addLayer(new L.OpenStreetBugs());
</script>
</body>
</html>

View file

@ -1,21 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../layer/vector/OSM.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(55.7, 37.6), zoom: 9, zoomAnimation: false });
map.addLayer(new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'));
var layer = new L.OSM('ulugo.osm')
.on("loaded", function(e) { map.fitBounds(e.target.getBounds()); });
map.addLayer(layer);
map.addControl(new L.Control.Layers({}, {"OSM":layer}));
</script>
</body>
</html>

View file

@ -1,23 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="../control/Permalink.js"></script>
<script src="../control/Permalink.Marker.js"></script>
<script src="../control/Permalink.Layer.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(67.6755, 33.936), zoom: 10});
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
map.addLayer(osm);
var kosm = new L.TileLayer('http://{s}.tile.osmosnimki.ru/kosmo/{z}/{x}/{y}.png', {attribution:'Tiles Courtesy of <a href="http://kosmosnimki.ru/" target="_blank">kosmosnimki.ru</a>'});
var layers = new L.Control.Layers({'OSM':osm, "Kosmo":kosm});
map.addControl(layers);
map.addControl(new L.Control.Permalink({text: 'Permalink', layers: layers}));
</script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -1,24 +0,0 @@
<html>
<head>
<title>Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="http://api-maps.yandex.ru/2.0/?load=package.map&lang=ru-RU" type="text/javascript"></script>
<script src="../layer/tile/Yandex.js"></script>
</head>
<body>
<div style="width:100%; height:100%" id="map"></div>
<script type='text/javascript'>
var map = new L.Map('map', {center: new L.LatLng(67.6755, 33.936), zoom: 10, zoomAnimation: false });
var osm = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
var yndx = new L.Yandex();
var ytraffic = new L.Yandex("null", {traffic:true, opacity:0.8, overlay:true});
map.addLayer(osm);
map.addLayer(ytraffic);
map.addControl(new L.Control.Layers({'OSM':osm, "Yandex":yndx},
{"Traffic":ytraffic}));
</script>
</body>
</html>

View file

@ -1,27 +0,0 @@
L.Icon.Canvas = L.Icon.extend({
options: {
iconSize: new L.Point(20, 20), // Have to be supplied
/*
iconAnchor: (Point)
popupAnchor: (Point)
*/
className: 'leaflet-canvas-icon'
},
createIcon: function () {
var e = document.createElement('canvas');
this._setIconStyles(e, 'icon');
var s = this.options.iconSize;
e.width = s.x;
e.height = s.y;
this.draw(e.getContext('2d'), s.x, s.y);
return e;
},
createShadow: function () {
return null;
},
draw: function(canvas, width, height) {
}
});

View file

@ -1,57 +0,0 @@
L.DeferredLayer = L.LayerGroup.extend({
options: {
js: [],
init: null
},
_script_cache: {},
initialize: function(options) {
L.Util.setOptions(this, options);
L.LayerGroup.prototype.initialize.apply(this);
this._loaded = false;
},
onAdd: function(map) {
L.LayerGroup.prototype.onAdd.apply(this, [map]);
if (this._loaded) return;
//console.info('Script cache', this._script_cache);
var loaded = function() {
//console.info('Loaded', this, this.options);
this._loaded = true;
var l = this.options.init();
if (l)
this.addLayer(l);
};
this._loadScripts(this.options.js.reverse(), L.Util.bind(loaded, this));
},
_loadScripts: function(scripts, cb, args) {
if (!scripts || scripts.length === 0)
return cb(args);
var _this = this, s = scripts.pop(), c;
c = this._script_cache[s];
if (c === undefined) {
c = {url: s, wait: []};
//console.info('Load ', s);
var script = document.createElement('script');
script.src = s;
script.type = 'text/javascript';
script.onload = function () {
//console.info('Element(cb)', c.e.readyState);
c.e.readyState = 'completed';
var i = 0;
for (i = 0; i < c.wait.length; i++)
c.wait[i]();
};
c.e = script;
document.getElementsByTagName('head')[0].appendChild(script);
}
function _cb() { _this._loadScripts(scripts, cb, args); }
c.wait.push(_cb);
//console.info('Element', c.e.readyState);
if (c.e.readyState === 'completed')
_cb();
this._script_cache[s] = c;
}
});

View file

@ -1,51 +0,0 @@
/*
* Based on comments by @runanet and @coomsie
* https://github.com/CloudMade/Leaflet/issues/386
*
* Wrapping function is needed to preserve L.Marker.update function
*/
(function () {
var _old__setPos = L.Marker.prototype._setPos;
L.Marker.include({
_updateImg: function(i, a, s) {
a = L.point(s).divideBy(2)._subtract(L.point(a));
var transform = '';
transform += ' translate(' + -a.x + 'px, ' + -a.y + 'px)';
transform += ' rotate(' + this.options.iconAngle + 'deg)';
transform += ' translate(' + a.x + 'px, ' + a.y + 'px)';
i.style[L.DomUtil.TRANSFORM] += transform;
},
setIconAngle: function (iconAngle) {
this.options.iconAngle = iconAngle;
if (this._map)
this.update();
},
_setPos: function (pos) {
if (this._icon)
this._icon.style[L.DomUtil.TRANSFORM] = '';
if (this._shadow)
this._shadow.style[L.DomUtil.TRANSFORM] = '';
_old__setPos.apply(this,[pos]);
if (this.options.iconAngle) {
var a = this.options.icon.options.iconAnchor;
var s = this.options.icon.options.iconSize;
var i;
if (this._icon) {
i = this._icon;
this._updateImg(i, a, s);
}
if (this._shadow) {
if (this.options.icon.options.shadowAnchor)
a = this.options.icon.options.shadowAnchor;
s = this.options.icon.options.shadowSize;
i = this._shadow;
this._updateImg(i, a, s);
}
}
}
});
}());

View file

@ -1,51 +0,0 @@
L.Icon.Text = L.Icon.extend({
initialize: function (text, options) {
this._text = text;
L.Icon.prototype.initialize.apply(this, [options]);
},
createIcon: function() {
var el = document.createElement('div');
el.appendChild(document.createTextNode(this._text));
this._setIconStyles(el, 'icon');
el.style.textShadow = '2px 2px 2px #fff';
return el;
},
createShadow: function() { return null; }
});
L.Marker.Text = L.Marker.extend({
initialize: function (latlng, text, options) {
L.Marker.prototype.initialize.apply(this, [latlng, options]);
this._fakeicon = new L.Icon.Text(text);
},
_initIcon: function() {
L.Marker.prototype._initIcon.apply(this);
var i = this._icon, s = this._shadow, obj = this.options.icon;
this._icon = this._shadow = null;
this.options.icon = this._fakeicon;
L.Marker.prototype._initIcon.apply(this);
this.options.icon = obj;
if (s) {
s.parentNode.removeChild(s);
this._icon.appendChild(s);
}
i.parentNode.removeChild(i);
this._icon.appendChild(i);
var w = this._icon.clientWidth, h = this._icon.clientHeight;
this._icon.style.marginLeft = -w / 2 + 'px';
//this._icon.style.backgroundColor = "red";
var off = new L.Point(w/2, 0);
if (L.Browser.webkit) off.y = -h;
L.DomUtil.setPosition(i, off);
if (s) L.DomUtil.setPosition(s, off);
}
});

View file

@ -1,496 +0,0 @@
/* global alert: true */
L.OpenStreetBugs = L.FeatureGroup.extend({
options : {
serverURL : 'http://openstreetbugs.schokokeks.org/api/0.1/',
readonly : false,
setCookie : true,
username : 'NoName',
cookieLifetime : 1000,
cookiePath : null,
permalinkZoom : 14,
permalinkUrl: null,
opacity : 0.7,
showOpen: true,
showClosed: true,
iconOpen: 'http://openstreetbugs.schokokeks.org/client/open_bug_marker.png',
iconClosed:'http://openstreetbugs.schokokeks.org/client/closed_bug_marker.png',
iconActive: undefined,
editArea: 0.01,
popupOptions: {autoPan: false},
dblClick: true
},
initialize : function(options)
{
var tmp = L.Util.extend({}, this.options.popupOptions, (options || {}).popupOptions);
L.Util.setOptions(this, options);
this.options.popupOptions = tmp;
putAJAXMarker.layers.push(this);
this.bugs = {};
this._layers = {};
var username = this.get_cookie('osbUsername');
if (username)
this.options.username = username;
L.OpenStreetBugs.setCSS();
},
onAdd : function(map)
{
L.FeatureGroup.prototype.onAdd.apply(this, [map]);
this._map.on('moveend', this.loadBugs, this);
this.loadBugs();
if (!this.options.readonly) {
if (this.options.dblClick) {
map.doubleClickZoom.disable();
map.on('dblclick', this.addBug, this);
}
else {
map.on('click', this.addBug, this);
}
}
this.fire('add');
},
onRemove : function(map)
{
this._map.off('moveend', this.loadBugs, this);
this._iterateLayers(map.removeLayer, map);
delete this._map;
if (!this.options.readonly) {
if (this.options.dblClick) {
map.doubleClickZoom.enable();
map.off('dblclick', this.addBug, this);
}
else {
map.off('click', this.addBug, this);
}
}
this.fire('remove');
},
set_cookie : function(name, value)
{
var expires = (new Date((new Date()).getTime() + 604800000)).toGMTString(); // one week from now
document.cookie = name+'='+encodeURIComponent(value)+';';
},
get_cookie : function(name)
{
var cookies = (document.cookie || '').split(/;\s*/);
for(var i=0; i<cookies.length; i++)
{
var cookie = cookies[i].split('=');
if(cookie[0] === name)
return decodeURIComponent(cookie[1]);
}
return null;
},
loadBugs : function()
{
//if(!this.getVisibility())
// return true;
var bounds = this._map.getBounds();
if(!bounds) return false;
var sw = bounds.getSouthWest(), ne = bounds.getNorthEast();
function round(number, digits) {
var factor = Math.pow(10, digits);
return Math.round(number*factor)/factor;
}
this.apiRequest('getBugs'
+ '?t='+round(ne.lat, 5)
+ '&r='+round(ne.lng, 5)
+ '&b='+round(sw.lat, 5)
+ '&l='+round(sw.lng, 5));
},
apiRequest : function(url, reload)
{
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = this.options.serverURL + url + '&nocache='+(new Date()).getTime();
var _this = this;
script.onload = function(e) {
document.body.removeChild(this);
if (reload) _this.loadBugs();
};
document.body.appendChild(script);
},
createMarker: function(id, force)
{
var bug = putAJAXMarker.bugs[id];
if(this.bugs[id])
{
if (force || this.bugs[id].osb.closed !== bug[2])
this.removeLayer(this.bugs[id]);
else
return;
}
var closed = bug[2];
if (closed && !this.options.showClosed) return;
if (!closed && !this.options.showOpen) return;
var icon_url = null;
var class_popup = ' osb';
if (bug[2]) {
icon_url = this.options.iconClosed;
class_popup += ' osbClosed';
}
else if (bug[1].length === 1) {
icon_url = this.options.iconOpen;
class_popup += ' osbOpen';
}
else {
if (this.options.iconActive) {
icon_url = this.options.iconActive;
class_popup += ' osbActive';
}
else {
icon_url = this.options.iconOpen;
class_popup += ' osbOpen';
}
}
var feature = new L.Marker(bug[0], {icon:new this.osbIcon({iconUrl: icon_url})});
feature.osb = {id: id, closed: closed};
this.addLayer(feature);
this.bugs[id] = feature;
this.setPopupContent(id);
feature._popup.options.className += class_popup;
if (this.options.bugid && (parseInt(this.options.bugid) === id))
feature.openPopup();
//this.events.triggerEvent('markerAdded');
},
osbIcon : L.Icon.extend({
options: {
iconUrl: 'http://openstreetbugs.schokokeks.org/client/open_bug_marker.png',
iconSize: new L.Point(22, 22),
shadowSize: new L.Point(0, 0),
iconAnchor: new L.Point(11, 11),
popupAnchor: new L.Point(0, -11)
}
}),
setPopupContent: function(id) {
if(this.bugs[id]._popup_content)
return;
var el1,el2,el3;
var layer = this;
var rawbug = putAJAXMarker.bugs[id];
var isclosed = rawbug[2];
var newContent = L.DomUtil.create('div', 'osb-popup');
var h1 = L.DomUtil.create('h1', null, newContent);
if (rawbug[2])
h1.textContent = L.i18n('Fixed Error');
else if (rawbug[1].length === 1)
h1.textContent = L.i18n('Unresolved Error');
else
h1.textContent = L.i18n('Active Error');
var divinfo = L.DomUtil.create('div', 'osb-info', newContent);
var table = L.DomUtil.create('table', 'osb-table', divinfo);
for(var i=0; i<rawbug[1].length; i++)
{
var tr = L.DomUtil.create('tr', 'osb-tr-info', table);
tr.setAttribute('valign','top');
var td_nickname = L.DomUtil.create('td', 'osb-td-nickname', tr);
td_nickname.textContent = rawbug[5][i] + ':';
var td_datetime = L.DomUtil.create('td', 'osb-td-datetime', tr);
td_datetime.textContent = rawbug[6][i];
var td_comment = L.DomUtil.create('td', 'osb-td-comment', L.DomUtil.create('tr', 'osb-tr-comment', table));
td_comment.setAttribute('colspan','2');
td_comment.setAttribute('charoff','2');
td_comment.textContent = rawbug[4][i];
}
function create_link(ul, text) {
var a = L.DomUtil.create('a', null,
L.DomUtil.create('li', null, ul));
a.href = '#';
a.textContent = L.i18n(text);
return a;
}
var ul = L.DomUtil.create('ul', null, newContent);
var _this = this;
var bug = this.bugs[id];
function showComment(title, add_comment) {
h1.textContent_old = h1.textContent;
h1.textContent = L.i18n(title);
var form = _this.createCommentForm();
form.osbid.value = id;
form.cancel.onclick = function (e) {
h1.textContent = h1.textContent_old;
newContent.removeChild(form);
newContent.appendChild(ul);
};
form.ok.onclick = function(e) {
bug.closePopup();
if (!add_comment)
_this.closeBug(form);
else
_this.submitComment(form);
return false;
};
newContent.appendChild(form);
newContent.removeChild(ul);
return false;
}
if (!isclosed && !this.options.readonly) {
var a;
a = create_link(ul, 'Add comment');
a.onclick = function(e) { return showComment('Add comment', true); };
a = create_link(ul, 'Mark as Fixed');
a.onclick = function(e) { return showComment('Close bug', false); };
}
var a_josm = create_link(ul, 'JOSM');
a_josm.onclick = function() { _this.remoteEdit(rawbug[0]); };
var a_link = create_link(ul, 'Link');
var vars = {lat:rawbug[0].lat, lon:rawbug[0].lng, zoom:this.options.permalinkZoom, bugid:id};
if (this.options.permalinkUrl)
a_link.href = L.Util.template(this.options.permalinkUrl, vars);
else
a_link.href = location.protocol + '//' + location.host + location.pathname +
L.Util.getParamString(vars);
bug._popup_content = newContent;
bug.bindPopup(newContent, this.options.popupOptions);
bug._popup.options.maxWidth=410;
bug._popup.options.minWidth=410;
bug.on('mouseover', bug.openTempPopup, bug);
},
submitComment: function(form) {
if (!form.osbcomment.value) return;
var nickname = form.osbnickname.value || this.options.username;
this.apiRequest('editPOIexec'
+ '?id='+encodeURIComponent(form.osbid.value)
+ '&text='+encodeURIComponent(form.osbcomment.value + ' [' + nickname + ']')
+ '&format=js', true
);
this.set_cookie('osbUsername',nickname);
this.options.username=nickname;
},
closeBug: function(form) {
var id = form.osbid.value;
this.submitComment(form);
this.apiRequest('closePOIexec'
+ '?id='+encodeURIComponent(id)
+ '&format=js', true
);
},
createCommentForm: function(elt) {
var form = L.DomUtil.create('form', 'osb-add-comment', elt);
var content = '';
content += '<input name="osbid" type="hidden"/>';
content += '<input name="osblat" type="hidden"/>';
content += '<input name="osblon" type="hidden"/>';
content += '<div><span class="osb-inputlabel">'+L.i18n('Nickname')+':</span><input type="text" name="osbnickname"></div>';
content += '<div><span class="osb-inputlabel">'+L.i18n('Comment')+':</span><input type="text" name="osbcomment"></div>';
content += '<div class="osb-formfooter"><input type="submit" name="ok"/><input type="button" name="cancel"/></div>';
form.innerHTML = content;
form.ok.value = L.i18n('OK');
form.cancel.value = L.i18n('Cancel');
form.osbnickname.value = this.options.username;
return form;
},
addBug: function(e) {
var newContent = L.DomUtil.create('div', 'osb-popup');
newContent.innerHTML += '<h1>'+L.i18n('New bug')+'</h1>';
newContent.innerHTML += '<div class="osbCreateInfo">'+L.i18n('Find your bug?')+'<br />'+L.i18n('Contact details and someone will fix it.')+'</div>';
var popup = new L.Popup();
var _this = this;
var form = this.createCommentForm(newContent);
form.osblat.value = e.latlng.lat;
form.osblon.value = e.latlng.lng;
form.ok.value = L.i18n('Add comment');
form.onsubmit = function(e) {
_this._map.closePopup(popup);
_this.createBug(form);
return false;
};
form.cancel.onclick = function(e) { _this._map.closePopup(popup); };
popup.setLatLng(e.latlng);
popup.setContent(newContent);
popup.options.maxWidth=410;
popup.options.minWidth=410;
popup.options.className += ' osb osbCreate';
this._map.openPopup(popup);
},
createBug: function(form) {
if (!form.osbcomment.value) return;
var nickname = form.osbnickname.value || this.options.username;
this.apiRequest('addPOIexec'
+ '?lat='+encodeURIComponent(form.osblat.value)
+ '&lon='+encodeURIComponent(form.osblon.value)
+ '&text='+encodeURIComponent(form.osbcomment.value + ' [' + nickname + ']')
+ '&format=js', true
);
this.set_cookie('osbUsername',nickname);
this.options.username=nickname;
},
remoteEdit: function(x) {
var ydelta = this.options.editArea || 0.01;
var xdelta = ydelta * 2;
var p = [ 'left=' + (x.lng - xdelta), 'bottom=' + (x.lat - ydelta), 'right=' + (x.lng + xdelta), 'top=' + (x.lat + ydelta)];
var url = 'http://localhost:8111/load_and_zoom?' + p.join('&');
var frame = L.DomUtil.create('iframe', null);
frame.style.display = 'none';
frame.src = url;
document.body.appendChild(frame);
frame.onload = function(e) { document.body.removeChild(frame); };
return false;
}
});
L.OpenStreetBugs.setCSS = function() {
if(L.OpenStreetBugs.setCSS.done)
return;
else
L.OpenStreetBugs.setCSS.done = true;
// See http://www.hunlock.com/blogs/Totally_Pwn_CSS_with_Javascript
var idx = 0;
var addRule = function(selector, rules) {
var s = document.styleSheets[0];
var rule;
if(s.addRule) // M$IE
rule = s.addRule(selector, rules, idx);
else
rule = s.insertRule(selector + ' { ' + rules + ' }', idx);
s.style = L.Util.extend(s.style || {}, rules);
idx++;
};
addRule('.osb-popup dl', 'margin:0; padding:0;');
addRule('.osb-popup dt', 'margin:0; padding:0; font-weight:bold; float:left; clear:left;');
addRule('.osb-popup dt:after', 'content: ": ";');
addRule('* html .osb-popup dt', 'margin-right:1ex;');
addRule('.osb-popup dd', 'margin:0; padding:0;');
addRule('.osb-popup ul.buttons', 'list-style-type:none; padding:0; margin:0;');
addRule('.osb-popup ul.buttons li', 'display:inline; margin:0; padding:0;');
addRule('.osb-popup h3', 'font-size:1.2em; margin:.2em 0 .7em 0;');
};
function putAJAXMarker(id, lon, lat, text, closed)
{
var comments = text.split(/<hr \/>/);
var comments_only = [];
var nickname = [];
var datetime = [];
var info = null;
var isplit = 0;
var i;
for(i=0; i<comments.length; i++) {
info = null;
isplit = 0;
comments[i] = comments[i].replace(/&quot;/g, '"').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
isplit = comments[i].lastIndexOf('[');
if (isplit > 0) {
comments_only[i] = comments[i].substr(0,isplit-1);
info = comments[i].substr(isplit+1);
nickname[i] = info.substr(0,info.lastIndexOf(','));
datetime[i] = info.substr(info.lastIndexOf(',')+2);
datetime[i] = datetime[i].substr(0,datetime[i].lastIndexOf(']'));
}
else {
comments_only[i] = comments[i];
}
}
var old = putAJAXMarker.bugs[id];
putAJAXMarker.bugs[id] = [
new L.LatLng(lat, lon),
comments,
closed,
text,
comments_only,
nickname,
datetime
];
var force = (old && old[3]) !== text;
for(i=0; i<putAJAXMarker.layers.length; i++)
putAJAXMarker.layers[i].createMarker(id, force);
}
function osbResponse(error)
{
if(error)
alert('Error: '+error);
return;
}
putAJAXMarker.layers = [ ];
putAJAXMarker.bugs = { };
L.Marker.include({
openTempPopup: function() {
this.openPopup();
this.off('click', this.openPopup, this);
function onclick() {
this.off('mouseout', onout, this);
this.off('click', onclick, this);
this.on('click', this.openPopup, this);
}
function onout() {
onclick.call(this);
this.closePopup();
}
this.on('mouseout', onout, this);
this.on('click', onclick, this);
}
});
L.i18n = function(s) { return (L.i18n.lang[L.i18n.current] || {})[s] || s; };
L.i18n.current = 'ru';
L.i18n.lang = {};
L.i18n.extend = function(lang, args) {
L.i18n.lang[lang] = L.Util.extend(L.i18n.lang[lang] || {}, args);
};
L.i18n.extend('ru', {
'Fixed Error':'Ошибка исправлена',
'Unresolved Error':'Неисправленная ошибка',
'Active Error':'Ошибка уточняется',
'Description':'Описание',
'Comment':'Описание',
'Add comment':'Дополнить',
'Mark as Fixed':'Исправлено',
'Link':'Ссылка',
'Cancel':'Отмена',
'New bug':'Я нашел ошибку',
'Find your bug?':'Нашли ошибку?',
'Contact details and someone will fix it.':'Напишите подробнее и кто-нибудь её исправит.'
});

View file

@ -1,125 +0,0 @@
/* global console: true */
L.BingLayer = L.TileLayer.extend({
options: {
subdomains: [0, 1, 2, 3],
type: 'Aerial',
attribution: 'Bing',
culture: ''
},
initialize: function(key, options) {
L.Util.setOptions(this, options);
this._key = key;
this._url = null;
this.meta = {};
this.loadMetadata();
},
tile2quad: function(x, y, z) {
var quad = '';
for (var i = z; i > 0; i--) {
var digit = 0;
var mask = 1 << (i - 1);
if ((x & mask) !== 0) digit += 1;
if ((y & mask) !== 0) digit += 2;
quad = quad + digit;
}
return quad;
},
getTileUrl: function(p, z) {
var zoom = this._getZoomForUrl();
var subdomains = this.options.subdomains,
s = this.options.subdomains[Math.abs((p.x + p.y) % subdomains.length)];
return this._url.replace('{subdomain}', s)
.replace('{quadkey}', this.tile2quad(p.x, p.y, zoom))
.replace('{culture}', this.options.culture);
},
loadMetadata: function() {
var _this = this;
var cbid = '_bing_metadata_' + L.Util.stamp(this);
window[cbid] = function (meta) {
_this.meta = meta;
window[cbid] = undefined;
var e = document.getElementById(cbid);
e.parentNode.removeChild(e);
if (meta.errorDetails) {
if (window.console) console.log('Leaflet Bing Plugin Error - Got metadata: ' + meta.errorDetails);
return;
}
_this.initMetadata();
};
var url = document.location.protocol + '//dev.virtualearth.net/REST/v1/Imagery/Metadata/' + this.options.type + '?include=ImageryProviders&jsonp=' + cbid +
'&key=' + this._key + '&UriScheme=' + document.location.protocol.slice(0, -1);
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.id = cbid;
document.getElementsByTagName('head')[0].appendChild(script);
},
initMetadata: function() {
var r = this.meta.resourceSets[0].resources[0];
this.options.subdomains = r.imageUrlSubdomains;
this._url = r.imageUrl;
this._providers = [];
if (r.imageryProviders) {
for (var i = 0; i < r.imageryProviders.length; i++) {
var p = r.imageryProviders[i];
for (var j = 0; j < p.coverageAreas.length; j++) {
var c = p.coverageAreas[j];
var coverage = {zoomMin: c.zoomMin, zoomMax: c.zoomMax, active: false};
var bounds = new L.LatLngBounds(
new L.LatLng(c.bbox[0]+0.01, c.bbox[1]+0.01),
new L.LatLng(c.bbox[2]-0.01, c.bbox[3]-0.01)
);
coverage.bounds = bounds;
coverage.attrib = p.attribution;
this._providers.push(coverage);
}
}
}
this._update();
},
_update: function() {
if (this._url === null || !this._map) return;
this._update_attribution();
L.TileLayer.prototype._update.apply(this, []);
},
_update_attribution: function() {
var bounds = this._map.getBounds();
var zoom = this._map.getZoom();
for (var i = 0; i < this._providers.length; i++) {
var p = this._providers[i];
if ((zoom <= p.zoomMax && zoom >= p.zoomMin) &&
bounds.intersects(p.bounds)) {
if (!p.active && this._map.attributionControl)
this._map.attributionControl.addAttribution(p.attrib);
p.active = true;
} else {
if (p.active && this._map.attributionControl)
this._map.attributionControl.removeAttribution(p.attrib);
p.active = false;
}
}
},
onRemove: function(map) {
for (var i = 0; i < this._providers.length; i++) {
var p = this._providers[i];
if (p.active && this._map.attributionControl) {
this._map.attributionControl.removeAttribution(p.attrib);
p.active = false;
}
}
L.TileLayer.prototype.onRemove.apply(this, [map]);
}
});
L.bingLayer = function (key, options) {
return new L.BingLayer(key, options);
};

View file

@ -1,200 +0,0 @@
/*
* Google layer using Google Maps API
*/
/* global google: true */
L.Google = L.Class.extend({
includes: L.Mixin.Events,
options: {
minZoom: 0,
maxZoom: 18,
tileSize: 256,
subdomains: 'abc',
errorTileUrl: '',
attribution: '',
opacity: 1,
continuousWorld: false,
noWrap: false,
mapOptions: {
backgroundColor: '#dddddd'
}
},
// Possible types: SATELLITE, ROADMAP, HYBRID, TERRAIN
initialize: function(type, options) {
L.Util.setOptions(this, options);
this._ready = google.maps.Map !== undefined;
if (!this._ready) L.Google.asyncWait.push(this);
this._type = type || 'SATELLITE';
},
onAdd: function(map, insertAtTheBottom) {
this._map = map;
this._insertAtTheBottom = insertAtTheBottom;
// create a container div for tiles
this._initContainer();
this._initMapObject();
// set up events
map.on('viewreset', this._resetCallback, this);
this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
map.on('move', this._update, this);
map.on('zoomanim', this._handleZoomAnim, this);
//20px instead of 1em to avoid a slight overlap with google's attribution
map._controlCorners.bottomright.style.marginBottom = '20px';
this._reset();
this._update();
},
onRemove: function(map) {
this._map._container.removeChild(this._container);
//this._container = null;
this._map.off('viewreset', this._resetCallback, this);
this._map.off('move', this._update, this);
this._map.off('zoomanim', this._handleZoomAnim, this);
map._controlCorners.bottomright.style.marginBottom = '0em';
//this._map.off('moveend', this._update, this);
},
getAttribution: function() {
return this.options.attribution;
},
setOpacity: function(opacity) {
this.options.opacity = opacity;
if (opacity < 1) {
L.DomUtil.setOpacity(this._container, opacity);
}
},
setElementSize: function(e, size) {
e.style.width = size.x + 'px';
e.style.height = size.y + 'px';
},
_initContainer: function() {
var tilePane = this._map._container,
first = tilePane.firstChild;
if (!this._container) {
this._container = L.DomUtil.create('div', 'leaflet-google-layer leaflet-top leaflet-left');
this._container.id = '_GMapContainer_' + L.Util.stamp(this);
this._container.style.zIndex = 'auto';
}
tilePane.insertBefore(this._container, first);
this.setOpacity(this.options.opacity);
this.setElementSize(this._container, this._map.getSize());
},
_initMapObject: function() {
if (!this._ready) return;
this._google_center = new google.maps.LatLng(0, 0);
var map = new google.maps.Map(this._container, {
center: this._google_center,
zoom: 0,
tilt: 0,
mapTypeId: google.maps.MapTypeId[this._type],
disableDefaultUI: true,
keyboardShortcuts: false,
draggable: false,
disableDoubleClickZoom: true,
scrollwheel: false,
streetViewControl: false,
styles: this.options.mapOptions.styles,
backgroundColor: this.options.mapOptions.backgroundColor
});
var _this = this;
this._reposition = google.maps.event.addListenerOnce(map, 'center_changed',
function() { _this.onReposition(); });
this._google = map;
google.maps.event.addListenerOnce(map, 'idle',
function() { _this._checkZoomLevels(); });
},
_checkZoomLevels: function() {
//setting the zoom level on the Google map may result in a different zoom level than the one requested
//(it won't go beyond the level for which they have data).
// verify and make sure the zoom levels on both Leaflet and Google maps are consistent
if (this._google.getZoom() !== this._map.getZoom()) {
//zoom levels are out of sync. Set the leaflet zoom level to match the google one
this._map.setZoom( this._google.getZoom() );
}
},
_resetCallback: function(e) {
this._reset(e.hard);
},
_reset: function(clearOldContainer) {
this._initContainer();
},
_update: function(e) {
if (!this._google) return;
this._resize();
var center = e && e.latlng ? e.latlng : this._map.getCenter();
var _center = new google.maps.LatLng(center.lat, center.lng);
this._google.setCenter(_center);
this._google.setZoom(this._map.getZoom());
this._checkZoomLevels();
//this._google.fitBounds(google_bounds);
},
_resize: function() {
var size = this._map.getSize();
if (this._container.style.width === size.x &&
this._container.style.height === size.y)
return;
this.setElementSize(this._container, size);
this.onReposition();
},
_handleZoomAnim: function (e) {
var center = e.center;
var _center = new google.maps.LatLng(center.lat, center.lng);
this._google.setCenter(_center);
this._google.setZoom(e.zoom);
},
onReposition: function() {
if (!this._google) return;
google.maps.event.trigger(this._google, 'resize');
}
});
L.Google.asyncWait = [];
L.Google.asyncInitialize = function() {
var i;
for (i = 0; i < L.Google.asyncWait.length; i++) {
var o = L.Google.asyncWait[i];
o._ready = true;
if (o._container) {
o._initMapObject();
o._update();
}
}
L.Google.asyncWait = [];
};

View file

@ -1,161 +0,0 @@
/*
* L.TileLayer is used for standard xyz-numbered tile layers.
*/
/* global ymaps: true */
/* global console: true */
L.Yandex = L.Class.extend({
includes: L.Mixin.Events,
options: {
minZoom: 0,
maxZoom: 18,
attribution: '',
opacity: 1,
traffic: false
},
// Possible types: map, satellite, hybrid, publicMap, publicMapHybrid
initialize: function(type, options) {
L.Util.setOptions(this, options);
this._type = 'yandex#' + (type || 'map');
},
onAdd: function(map, insertAtTheBottom) {
this._map = map;
this._insertAtTheBottom = insertAtTheBottom;
// create a container div for tiles
this._initContainer();
this._initMapObject();
// set up events
map.on('viewreset', this._resetCallback, this);
this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
map.on('move', this._update, this);
map._controlCorners.bottomright.style.marginBottom = '3em';
this._reset();
this._update(true);
},
onRemove: function(map) {
this._map._container.removeChild(this._container);
this._map.off('viewreset', this._resetCallback, this);
this._map.off('move', this._update, this);
map._controlCorners.bottomright.style.marginBottom = '0em';
},
getAttribution: function() {
return this.options.attribution;
},
setOpacity: function(opacity) {
this.options.opacity = opacity;
if (opacity < 1) {
L.DomUtil.setOpacity(this._container, opacity);
}
},
setElementSize: function(e, size) {
e.style.width = size.x + 'px';
e.style.height = size.y + 'px';
},
_initContainer: function() {
var tilePane = this._map._container,
first = tilePane.firstChild;
if (!this._container) {
this._container = L.DomUtil.create('div', 'leaflet-yandex-layer leaflet-top leaflet-left');
this._container.id = '_YMapContainer_' + L.Util.stamp(this);
this._container.style.zIndex = 'auto';
}
if (this.options.overlay) {
first = this._map._container.getElementsByClassName('leaflet-map-pane')[0];
first = first.nextSibling;
// XXX: Bug with layer order
if (L.Browser.opera)
this._container.className += ' leaflet-objects-pane';
}
tilePane.insertBefore(this._container, first);
this.setOpacity(this.options.opacity);
this.setElementSize(this._container, this._map.getSize());
},
_initMapObject: function() {
if (this._yandex) return;
// Check that ymaps.Map is ready
if (ymaps.Map === undefined) {
if (console) {
console.debug('L.Yandex: Waiting on ymaps.load("package.map")');
}
return ymaps.load(['package.map'], this._initMapObject, this);
}
// If traffic layer is requested check if control.TrafficControl is ready
if (this.options.traffic)
if (ymaps.control === undefined ||
ymaps.control.TrafficControl === undefined) {
if (console) {
console.debug('L.Yandex: loading traffic and controls');
}
return ymaps.load(['package.traffic', 'package.controls'],
this._initMapObject, this);
}
var map = new ymaps.Map(this._container, {center: [0,0], zoom: 0, behaviors: []});
if (this.options.traffic)
map.controls.add(new ymaps.control.TrafficControl({shown: true}));
if (this._type === 'yandex#null') {
this._type = new ymaps.MapType('null', []);
map.container.getElement().style.background = 'transparent';
}
map.setType(this._type);
this._yandex = map;
this._update(true);
},
_resetCallback: function(e) {
this._reset(e.hard);
},
_reset: function(clearOldContainer) {
this._initContainer();
},
_update: function(force) {
if (!this._yandex) return;
this._resize(force);
var center = this._map.getCenter();
var _center = [center.lat, center.lng];
var zoom = this._map.getZoom();
if (force || this._yandex.getZoom() !== zoom)
this._yandex.setZoom(zoom);
this._yandex.panTo(_center, {duration: 0, delay: 0});
},
_resize: function(force) {
var size = this._map.getSize(), style = this._container.style;
if (style.width === size.x + 'px' && style.height === size.y + 'px')
if (force !== true) return;
this.setElementSize(this._container, size);
var b = this._map.getBounds(), sw = b.getSouthWest(), ne = b.getNorthEast();
this._yandex.container.fitToViewport();
}
});

View file

@ -1,80 +0,0 @@
//#include 'GPX.js'
(function() {
function d2h(d) {
var hex = '0123456789ABCDEF';
var r = '';
d = Math.floor(d);
while (d !== 0) {
r = hex[d % 16] + r;
d = Math.floor(d / 16);
}
while (r.length < 2) r = '0' + r;
return r;
}
function gradient(color) {
// First arc (0, PI) in HSV colorspace
function f2h(d) { return d2h(256 * d); }
if (color < 0)
return '#FF0000';
else if (color < 1.0/3)
return '#FF' + f2h(3 * color) + '00';
else if (color < 2.0/3)
return '#' + f2h(2 - 3 * color) + 'FF00';
else if (color < 1)
return '#00FF' + f2h(3 * color - 2);
else
return '#00FFFF';
}
function gpx2time(s) {
// 2011-09-24T12:07:53Z
if (s.length !== 10 + 1 + 8 + 1)
return new Date();
return new Date(s);
}
L.GPX.include({
options: {
maxSpeed: 110,
chunks: 200
},
speedSplitEnable: function(options) {
L.Util.setOptions(this, options);
return this.on('addline', this.speed_split, this);
},
speedSplitDisable: function() {
return this.off('addline', this.speed_split, this);
},
speed_split: function(e) {
var l = e.line.pop(), ll = l.getLatLngs();
var chunk = Math.floor(ll.length / this.options.chunks);
if (chunk < 3) chunk = 3;
var p = null;
for (var i = 0; i < ll.length; i += chunk) {
var d = 0, t = null;
if (i + chunk > ll.length)
chunk = ll.length - i;
for (var j = 0; j < chunk; j++) {
if (p) d += p.distanceTo(ll[i+j]);
p = ll[i + j];
if (!t) t = gpx2time(p.meta.time);
}
p = ll[i + chunk - 1];
t = (gpx2time(p.meta.time) - t) / (3600 * 1000);
var speed = 0.001 * d / t;
//console.info('Dist: ' + d + '; Speed: ' + speed);
var color = gradient(speed / this.options.maxSpeed);
var poly = new L.Polyline(ll.slice(i, i+chunk+1), {color: color, weight: 2, opacity: 1});
poly.bindPopup('Dist: ' + d.toFixed() + 'm; Speed: ' + speed.toFixed(2) + ' km/h');
e.line.push(poly);
}
}
});
})();

View file

@ -1,141 +0,0 @@
L.GPX = L.FeatureGroup.extend({
initialize: function(gpx, options) {
L.Util.setOptions(this, options);
this._gpx = gpx;
this._layers = {};
if (gpx) {
this.addGPX(gpx, options, this.options.async);
}
},
loadXML: function(url, cb, options, async) {
if (async === undefined) async = this.options.async;
if (options === undefined) options = this.options;
var req = new window.XMLHttpRequest();
req.open('GET', url, async);
try {
req.overrideMimeType('text/xml'); // unsupported by IE
} catch(e) {}
req.onreadystatechange = function() {
if (req.readyState !== 4) return;
if(req.status === 200) cb(req.responseXML, options);
};
req.send(null);
},
_humanLen: function(l) {
if (l < 2000)
return l.toFixed(0) + ' m';
else
return (l/1000).toFixed(1) + ' km';
},
_polylineLen: function(line)//line is a L.Polyline()
{
var ll = line._latlngs;
var d = 0, p = null;
for (var i = 0; i < ll.length; i++)
{
if(i && p)
d += p.distanceTo(ll[i]);
p = ll[i];
}
return d;
},
addGPX: function(url, options, async) {
var _this = this;
var cb = function(gpx, options) { _this._addGPX(gpx, options); };
this.loadXML(url, cb, options, async);
},
_addGPX: function(gpx, options) {
var layers = this.parseGPX(gpx, options);
if (!layers) return;
this.addLayer(layers);
this.fire('loaded');
},
parseGPX: function(xml, options) {
var j, i, el, layers = [];
var named = false, tags = [['rte','rtept'], ['trkseg','trkpt']];
for (j = 0; j < tags.length; j++) {
el = xml.getElementsByTagName(tags[j][0]);
for (i = 0; i < el.length; i++) {
var l = this.parse_trkseg(el[i], xml, options, tags[j][1]);
for (var k = 0; k < l.length; k++) {
if (this.parse_name(el[i], l[k])) named = true;
layers.push(l[k]);
}
}
}
el = xml.getElementsByTagName('wpt');
if (options.display_wpt !== false) {
for (i = 0; i < el.length; i++) {
var marker = this.parse_wpt(el[i], xml, options);
if (!marker) continue;
if (this.parse_name(el[i], marker)) named = true;
layers.push(marker);
}
}
if (!layers.length) return;
var layer = layers[0];
if (layers.length > 1)
layer = new L.FeatureGroup(layers);
if (!named) this.parse_name(xml, layer);
return layer;
},
parse_name: function(xml, layer) {
var i, el, txt='', name, descr='', len=0;
el = xml.getElementsByTagName('name');
if (el.length)
name = el[0].childNodes[0].nodeValue;
el = xml.getElementsByTagName('desc');
for (i = 0; i < el.length; i++) {
for (var j = 0; j < el[i].childNodes.length; j++)
descr = descr + el[i].childNodes[j].nodeValue;
}
if(layer instanceof L.Path)
len = this._polylineLen(layer);
if (name) txt += '<h2>' + name + '</h2>' + descr;
if (len) txt += '<p>' + this._humanLen(len) + '</p>';
if (layer && layer._popup === undefined) layer.bindPopup(txt);
return txt;
},
parse_trkseg: function(line, xml, options, tag) {
var el = line.getElementsByTagName(tag);
if (!el.length) return [];
var coords = [];
for (var i = 0; i < el.length; i++) {
var ll = new L.LatLng(el[i].getAttribute('lat'),
el[i].getAttribute('lon'));
ll.meta = {};
for (var j in el[i].childNodes) {
var e = el[i].childNodes[j];
if (!e.tagName) continue;
ll.meta[e.tagName] = e.textContent;
}
coords.push(ll);
}
var l = [new L.Polyline(coords, options)];
this.fire('addline', {line:l});
return l;
},
parse_wpt: function(e, xml, options) {
var m = new L.Marker(new L.LatLng(e.getAttribute('lat'),
e.getAttribute('lon')), options);
this.fire('addpoint', {point:m});
return m;
}
});

View file

@ -1,355 +0,0 @@
L.KML = L.FeatureGroup.extend({
options: {
async: true
},
initialize: function(kml, options) {
L.Util.setOptions(this, options);
this._kml = kml;
this._layers = {};
if (kml) {
this.addKML(kml, options, this.options.async);
}
},
loadXML: function(url, cb, options, async) {
if (async === undefined) async = this.options.async;
if (options === undefined) options = this.options;
var req = new window.XMLHttpRequest();
req.open('GET', url, async);
try {
req.overrideMimeType('text/xml'); // unsupported by IE
} catch(e) {}
req.onreadystatechange = function() {
if (req.readyState !== 4) return;
if (req.status === 200) cb(req.responseXML, options);
};
req.send(null);
},
addKML: function(url, options, async) {
var _this = this;
var cb = function(gpx, options) { _this._addKML(gpx, options); };
this.loadXML(url, cb, options, async);
},
_addKML: function(xml, options) {
var layers = L.KML.parseKML(xml);
if (!layers || !layers.length) return;
for (var i = 0; i < layers.length; i++) {
this.fire('addlayer', {
layer: layers[i]
});
this.addLayer(layers[i]);
}
this.latLngs = L.KML.getLatLngs(xml);
this.fire('loaded');
},
latLngs: []
});
L.Util.extend(L.KML, {
parseKML: function (xml) {
var style = this.parseStyle(xml);
this.parseStyleMap(xml, style);
var el = xml.getElementsByTagName('Folder');
var layers = [], l;
for (var i = 0; i < el.length; i++) {
if (!this._check_folder(el[i])) { continue; }
l = this.parseFolder(el[i], style);
if (l) { layers.push(l); }
}
el = xml.getElementsByTagName('Placemark');
for (var j = 0; j < el.length; j++) {
if (!this._check_folder(el[j])) { continue; }
l = this.parsePlacemark(el[j], xml, style);
if (l) { layers.push(l); }
}
return layers;
},
// Return false if e's first parent Folder is not [folder]
// - returns true if no parent Folders
_check_folder: function (e, folder) {
e = e.parentElement;
while (e && e.tagName !== 'Folder')
{
e = e.parentElement;
}
return !e || e === folder;
},
parseStyle: function (xml) {
var style = {};
var sl = xml.getElementsByTagName('Style');
//for (var i = 0; i < sl.length; i++) {
var attributes = {color: true, width: true, Icon: true, href: true,
hotSpot: true};
function _parse(xml) {
var options = {};
for (var i = 0; i < xml.childNodes.length; i++) {
var e = xml.childNodes[i];
var key = e.tagName;
if (!attributes[key]) { continue; }
if (key === 'hotSpot')
{
for (var j = 0; j < e.attributes.length; j++) {
options[e.attributes[j].name] = e.attributes[j].nodeValue;
}
} else {
var value = e.childNodes[0].nodeValue;
if (key === 'color') {
options.opacity = parseInt(value.substring(0, 2), 16) / 255.0;
options.color = '#' + value.substring(6, 8) + value.substring(4, 6) + value.substring(2, 4);
} else if (key === 'width') {
options.weight = value;
} else if (key === 'Icon') {
ioptions = _parse(e);
if (ioptions.href) { options.href = ioptions.href; }
} else if (key === 'href') {
options.href = value;
}
}
}
return options;
}
for (var i = 0; i < sl.length; i++) {
var e = sl[i], el;
var options = {}, poptions = {}, ioptions = {};
el = e.getElementsByTagName('LineStyle');
if (el && el[0]) { options = _parse(el[0]); }
el = e.getElementsByTagName('PolyStyle');
if (el && el[0]) { poptions = _parse(el[0]); }
if (poptions.color) { options.fillColor = poptions.color; }
if (poptions.opacity) { options.fillOpacity = poptions.opacity; }
el = e.getElementsByTagName('IconStyle');
if (el && el[0]) { ioptions = _parse(el[0]); }
if (ioptions.href) {
// save anchor info until the image is loaded
options.icon = new L.KMLIcon({
iconUrl: ioptions.href,
shadowUrl: null,
iconAnchorRef: {x: ioptions.x, y: ioptions.y},
iconAnchorType: {x: ioptions.xunits, y: ioptions.yunits}
});
}
style['#' + e.getAttribute('id')] = options;
}
return style;
},
parseStyleMap: function (xml, existingStyles) {
var sl = xml.getElementsByTagName('StyleMap');
for (var i = 0; i < sl.length; i++) {
var e = sl[i], el;
var smKey, smStyleUrl;
el = e.getElementsByTagName('key');
if (el && el[0]) { smKey = el[0].textContent; }
el = e.getElementsByTagName('styleUrl');
if (el && el[0]) { smStyleUrl = el[0].textContent; }
if (smKey === 'normal')
{
existingStyles['#' + e.getAttribute('id')] = existingStyles[smStyleUrl];
}
}
return;
},
parseFolder: function (xml, style) {
var el, layers = [], l;
el = xml.getElementsByTagName('Folder');
for (var i = 0; i < el.length; i++) {
if (!this._check_folder(el[i], xml)) { continue; }
l = this.parseFolder(el[i], style);
if (l) { layers.push(l); }
}
el = xml.getElementsByTagName('Placemark');
for (var j = 0; j < el.length; j++) {
if (!this._check_folder(el[j], xml)) { continue; }
l = this.parsePlacemark(el[j], xml, style);
if (l) { layers.push(l); }
}
if (!layers.length) { return; }
if (layers.length === 1) { return layers[0]; }
return new L.FeatureGroup(layers);
},
parsePlacemark: function (place, xml, style) {
var i, j, el, options = {};
el = place.getElementsByTagName('styleUrl');
for (i = 0; i < el.length; i++) {
var url = el[i].childNodes[0].nodeValue;
for (var a in style[url])
{
// for jshint
if (true)
{
options[a] = style[url][a];
}
}
}
var layers = [];
var parse = ['LineString', 'Polygon', 'Point'];
for (j in parse) {
// for jshint
if (true)
{
var tag = parse[j];
el = place.getElementsByTagName(tag);
for (i = 0; i < el.length; i++) {
var l = this['parse' + tag](el[i], xml, options);
if (l) { layers.push(l); }
}
}
}
if (!layers.length) {
return;
}
var layer = layers[0];
if (layers.length > 1) {
layer = new L.FeatureGroup(layers);
}
var name, descr = '';
el = place.getElementsByTagName('name');
if (el.length && el[0].childNodes.length) {
name = el[0].childNodes[0].nodeValue;
}
el = place.getElementsByTagName('description');
for (i = 0; i < el.length; i++) {
for (j = 0; j < el[i].childNodes.length; j++) {
descr = descr + el[i].childNodes[j].nodeValue;
}
}
if (name) {
layer.bindPopup('<h2>' + name + '</h2>' + descr);
}
return layer;
},
parseCoords: function (xml) {
var el = xml.getElementsByTagName('coordinates');
return this._read_coords(el[0]);
},
parseLineString: function (line, xml, options) {
var coords = this.parseCoords(line);
if (!coords.length) { return; }
return new L.Polyline(coords, options);
},
parsePoint: function (line, xml, options) {
var el = line.getElementsByTagName('coordinates');
if (!el.length) {
return;
}
var ll = el[0].childNodes[0].nodeValue.split(',');
return new L.KMLMarker(new L.LatLng(ll[1], ll[0]), options);
},
parsePolygon: function (line, xml, options) {
var el, polys = [], inner = [], i, coords;
el = line.getElementsByTagName('outerBoundaryIs');
for (i = 0; i < el.length; i++) {
coords = this.parseCoords(el[i]);
if (coords) {
polys.push(coords);
}
}
el = line.getElementsByTagName('innerBoundaryIs');
for (i = 0; i < el.length; i++) {
coords = this.parseCoords(el[i]);
if (coords) {
inner.push(coords);
}
}
if (!polys.length) {
return;
}
if (options.fillColor) {
options.fill = true;
}
if (polys.length === 1) {
return new L.Polygon(polys.concat(inner), options);
}
return new L.MultiPolygon(polys, options);
},
getLatLngs: function (xml) {
var el = xml.getElementsByTagName('coordinates');
var coords = [];
for (var j = 0; j < el.length; j++) {
// text might span many childNodes
coords = coords.concat(this._read_coords(el[j]));
}
return coords;
},
_read_coords: function (el) {
var text = '', coords = [], i;
for (i = 0; i < el.childNodes.length; i++) {
text = text + el.childNodes[i].nodeValue;
}
text = text.split(/[\s\n]+/);
for (i = 0; i < text.length; i++) {
var ll = text[i].split(',');
if (ll.length < 2) {
continue;
}
coords.push(new L.LatLng(ll[1], ll[0]));
}
return coords;
}
});
L.KMLIcon = L.Icon.extend({
createIcon: function () {
var img = this._createIcon('icon');
img.onload = function () {
var i = img;
this.style.width = i.width + 'px';
this.style.height = i.height + 'px';
if (this.anchorType.x === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
img.style.marginLeft = (-this.anchor.x * i.width) + 'px';
}
if (this.anchorType.y === 'UNITS_FRACTION' || this.anchorType.x === 'fraction') {
img.style.marginTop = (-(1 - this.anchor.y) * i.height) + 'px';
}
this.style.display = '';
};
return img;
},
_setIconStyles: function (img, name) {
L.Icon.prototype._setIconStyles.apply(this, [img, name]);
// save anchor information to the image
img.anchor = this.options.iconAnchorRef;
img.anchorType = this.options.iconAnchorType;
}
});
L.KMLMarker = L.Marker.extend({
options: {
icon: new L.KMLIcon.Default()
}
});

View file

@ -1,173 +0,0 @@
/* global console: true */
L.OSM = L.FeatureGroup.extend({
options: {
async: true,
forceAll: false
},
initialize: function(url, options) {
L.Util.setOptions(this, options);
this._url = url;
this._layers = {};
if (url) {
this.addXML(url, options, this.options.async);
}
},
loadXML: function(url, cb, options, async) {
if (async === undefined) async = this.options.async;
if (options === undefined) options = this.options;
var req = new window.XMLHttpRequest();
req.open('GET', url, async);
req.overrideMimeType('text/xml');
req.onreadystatechange = function() {
if (req.readyState !== 4) return;
if (req.status === 200) cb(req.responseXML, options);
};
req.send(null);
},
addXML: function(url, options, async) {
var _this = this;
var cb = function(xml, options) { _this._addXML(xml, options); };
this.loadXML(url, cb, options, async);
},
_addXML: function(xml, options) {
var layers = this.parseOSM(xml, options);
if (!layers) return;
this.addLayer(layers);
this.fire('loaded');
},
parseOSM: function(xml, options) {
var i, el, ll, layers = [];
var nodes = {};
var ways = {};
var named = false;
el = xml.getElementsByTagName('node');
for (i = 0; i < el.length; i++) {
var l = this.parse_node(el[i], xml, options);
if (l === undefined) continue;
nodes[l.osmid] = l;
if (!this.options.forceAll && !l.tags.length) continue;
var m = this.named_node(l, options);
if (!ll) ll = m.getLatLng();
if (this.parse_name(m, l, 'Node')) named = true;
layers.push(m);
}
el = xml.getElementsByTagName('way');
for (i = 0; i < el.length; i++) {
if (i > 10) break;
var way = this.parse_way(el[i], nodes, options);
if (!way) continue;
if (!ll) ll = way.getLatLngs()[0];
if (this.parse_name(way, way, 'Way')) named = true;
layers.push(way);
ways[way.osmid] = way;
}
el = xml.getElementsByTagName('relation');
for (i = 0; i < el.length; i++) {
if (i > 10) break;
var relation = this.parse_relation(el[i], ways, options);
if (!relation) continue;
if (!ll) ll = relation.getLatLngs()[0];
if (this.parse_name(relation, relation, 'Relation')) named = true;
layers.push(relation);
}
if (!layers.length) return;
var layer = layers[0];
if (layers.length > 1)
layer = new L.FeatureGroup(layers);
if (!named) this.parse_name(xml, layer);
layer.focusPoint = ll;
return layer;
},
parse_name: function(layer, obj, obj_name) {
console.info('parse name');
console.info(this.options);
if (!this.options.forceAll)
if (!obj.tags || !obj.tags.length) return;
var i, txt = '<table>';
for (i = 0; i < obj.tags.length; i++) {
var t = obj.tags[i];
txt += '<tr><td>' + t.k + '</td><td>=</td><td>' + t.v + '</td></tr>';
}
txt += '</table>';
txt = '<h2>' + obj_name + ' ' + obj.osmid + '</h2>' + txt;
if (layer) layer.bindPopup(txt);
return txt;
},
parse_tags: function(line) {
var tags = [], el = line.getElementsByTagName('tag');
for (var i = 0; i < el.length; i++)
tags.push({k: el[i].getAttribute('k'), v: el[i].getAttribute('v')});
return tags;
},
parse_node: function(e) {
var n = { osmid: e.getAttribute('id'),
lat:e.getAttribute('lat'),
lon:e.getAttribute('lon')
};
n.ll = new L.LatLng(n.lat, n.lon);
n.tags = this.parse_tags(e);
return n;
},
parse_way: function(line, nodes, options) {
var el = line.getElementsByTagName('nd');
if (!el.length) return;
var coords = [], tags = [];
for (var i = 0; i < el.length; i++) {
var ref = el[i].getAttribute('ref'), n = nodes[ref];
if (!n) return;
coords.push(n.ll);
}
var layer = new L.Polyline(coords, options);
layer.tags = this.parse_tags(line);
layer.osmid = line.getAttribute('id');
return layer;
},
parse_relation: function(line, ways, options) {
var el = line.getElementsByTagName('member');
if (!el.length) return;
var rt, coords = [], tags = this.parse_tags(line);
var i;
for (i = 0; i < tags.length; i++)
if (tags[i].k === 'type') rt = tags[i].v;
if (rt !== 'multipolygon' && rt !== 'boundary' && rt !== 'waterway')
return;
for (i = 0; i < el.length; i++) {
var mt = el[i].getAttribute('type'), ref = el[i].getAttribute('ref');
if (mt !== 'way') continue;
var w = ways[ref];
console.info('Way: ' + ref + ' ' + w);
if (!w) return;
coords.push(w);
}
console.info('Coords: ' + coords.length);
if (!coords.length) return;
var layer = new L.MultiPolyline(coords, options);
layer.tags = this.parse_tags(line);
layer.osmid = line.getAttribute('id');
return layer;
},
named_node: function(node, options) {
var marker = new L.Marker(new L.LatLng(node.lat, node.lon), options);
return marker;
}
});

View file

@ -1,28 +0,0 @@
{
"author": "Pavel Shramov",
"name": "leaflet-plugins",
"version": "1.1.2",
"description": "Miscellaneous plugins for Leaflet library for services that need to display route information and need satellite imagery from different providers",
"repository": {
"type": "git",
"url": "git@github.com:shramov/leaflet-plugins.git"
},
"scripts": {
"test": "jshint control/* layer/*"
},
"devDependencies": {
"jshint": "2.5.0"
},
"contributors": [
"Bruno Bergot <bruno@eliaz.fr>",
"Andrey Lushchick <andrew@lushchick.org>"
],
"keywords": [
"leaflet",
"plugins",
"map",
"google",
"bing",
"yandex"
]
}

View file

@ -1,13 +0,0 @@
{
"name": "leaflet-routing",
"homepage": "https://github.com/nrenner/leaflet-routing",
"_release": "ed9a880cb3",
"_resolution": {
"type": "branch",
"branch": "styles",
"commit": "ed9a880cb353e1f2ef1c5de56bb2ac2758578663"
},
"_source": "git://github.com/nrenner/leaflet-routing.git",
"_target": "styles",
"_originalSource": "nrenner/leaflet-routing"
}

View file

@ -1 +0,0 @@
*.swp

View file

@ -1,41 +0,0 @@
Changelog
=========
### 0.2.0 (Unreadlesed)
**Features**
* Add option for overriding draw shortcuts (#23)
* Add option for disabling drawing marker (#18)
* Add options for tooltips (waypoint, segment)
* Disable shortcuts by setting `options.shortcut` to `false`.
* Add support for loading GeoJSON without waypoints (#16).
* Add option to #loadGeoJSON() to disable map fit bounds.
* Add [OSM demo](http://turistforeningen.github.io/leaflet-routing/examples/osm.html)
* …as well as countless updates to the readme and code readability.
**Breaking changes**
* Default shortcut key for draw enable is `d`
* Default shortcut key for draw disable is `q`
### 0.1.1 March 11, 2014
**Features**
* Add changelog overview (#14)
* Add Change map bounds when loading GeoJSON (#13)
**Bugfixes**
* Fix undefined evaluation when snapping layer is not avaiable (#15)
* Fail gracefully when loading invalid GeoJSON (#12)
### 0.1.0 March 10, 2014
* Implements `#loadGeoJSON()` method (#3)
#### Backwards compability note
* Format of `properties.waypoints` in `#toGeoJSON()` is changed according to #3.

View file

@ -1,22 +0,0 @@
Copyright (c) 2014, Den Norske Turistforening
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,183 +0,0 @@
Leaflet.Routing
===============
Leaflet.Routing is a routing controller for the popular Leaflet mapping
framework. The module provides an intuitive interface for routing paths between
waypoints using any user specified routing service. A demo using the OSM data
can be found
[here](http://turistforeningen.github.io/leaflet-routing/examples/osm.html).
![Prototype Routing using Leaflet](https://raw.github.com/Turistforeningen/leaflet-routing/gh-pages/images/promo.gif)
## Features
* Route handling interface for Leaflet
* Use your own routing backend, or OSM
## Usage
```javascript
var routing = new L.Routing({
position: 'topright'
,routing: {
router: myRouterFunction
}
,tooltips: {
waypoint: 'Waypoint. Drag to move; Click to remove.',
segment: 'Drag to create a new waypoint'
}
,styles: { // see http://leafletjs.com/reference.html#polyline-options
trailer: {} // drawing line
,track: {} // calculated route result
,nodata: {} // line when no result (error)
}
,snapping: {
layers: [mySnappingLayer]
,sensitivity: 15
,vertexonly: false
}
,shortcut: {
draw: {
enable: 68 // 'd'
,disable: 81 // 'q'
}
}
});
map.addControl(routing);
```
### Enable Drawing
```javascript
routing.draw(true);
```
### Enable Routing `NOT IMPLEMENTED`
```javascript
routing.routing(true);
```
### Enable Snapping `NOT IMPLEMETED`
```javascript
routing.snapping(true);
```
### Recalculate the complete route by routing each segment
```javascript
routing.rerouteAllSegments(callback);
```
### Get first waypoint
```javascript
var first = routing.getFirst();
```
### Get last waypoint
```javascript
var last = routing.getLast();
```
### Get all waypoints
```javascript
var waypointsArray = routing.getWaypoints();
```
### Routing to Polyline
```javascript
var polyline = routing.toPolyline();
```
### To GeoJSON
```javascript
var geoJSON3D = routing.toGeoJSON();
var geoJSON2D = routing.toGeoJSON(false);
```
### Load GeoJSON
Load GeoJSON with and without `properties.waypoints`.
#### Options
* `number` waypointDistance - distance between inserted waypoints for GeoJSON without waypoints.
* `boolean` fitBounds - fit map arround loaded GeoJSON.
```javascript
routing.loadGeoJSON(geojson, [options], function(err) {
if (err) {
console.log(err);
} else {
console.log('Finished loading GeoJSON');
}
});
```
## Events
All events form Leaflet.Routing is prefixed with `routing:`.
### Usage
```javascript
routing.on('routing:someEvent', function() {
console.log('routing:someEvent triggered');
});
```
### L.Routing Events
| Event name | Description |
|------------|-------------|
| `routing:draw-start` | Fired when drawing mode is started |
| `routing:draw-new` | Fired when drawing mode is started for a new route |
| `routing:draw-continue` | Fired when drawing mode is started for an existing route |
| `routing:draw-stop` | Fired when drawing mode ends |
| `routing:edit-start` | Fired when editing mode starts |
| `routing:edit-end` | Fired when editing mode ends |
### Waypoint Events
| Event name | Description |
|------------|-------------|
| `routing:routeWaypointStart` | Fired when a new or existing waypoint is created or moved |
| `routing:routeWaypointEnd` | Fired when routing is finished for new or moved waypoint |
### Segment Events
| Event name | Description |
|------------|-------------|
| `routing:rerouteAllSegmentsStart` | Fired when rerouting of all segments starts |
| `routing:rerouteAllSegmentsEnd` | Fired when rerouting of all segments completes |
## Copyright
Copyright (c) 2014, Den Norske Turistforening
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions
and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,68 +0,0 @@
#map {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
div.line-mouse-marker {
background-color: #ffffff;
border: 2px solid black;
border-radius: 10px;
}
#export {
position: absolute;
right: 10px;
top: 10px;
background-color: rgb(228,225,218);
border: 1px solid rgb(196, 196, 196);
padding: 10px;
z-index: 3000;
}
#search {
position: relative;
margin: 10px auto;
background-color: rgb(228,225,218);
border: 1px solid rgb(196, 196, 196);
padding: 10px;
z-index: 3000;
width: 300px;
}
#search input {
width: 240px;
}
.typeahead {
background-color: #fff;
}
.tt-dropdown-menu {
width: 240px;
padding: 8px 0;
background-color: #fff;
border: 1px solid #ccc;
}
.tt-suggestion {
padding: 3px 20px;
font-size: 18px;
line-height: 24px;
}
.tt-suggestion.tt-is-under-cursor {
color: #fff;
background-color: #0097cf;
}
.tt-suggestion p {
margin: 0;
}
#export input {
width: 70px;
}

View file

@ -1,228 +0,0 @@
/*
Routing capability using the Leaflet framework
Copyright (c) 2013, Turistforeningen, Hans Kristian Flaatten
https://github.com/Turistforeningen/leaflet-routing
*/
var routing, data;
(function() {
"use strict";
jQuery(function($) {
var api, apiKey, rUrl, sUrl, topo, map, snapping, inport, myRouter;
api = window.location.hash.substr(1).split('@');
if (api.length === 2) {
rUrl = 'http://' + api[1] + '/route/?coords='
sUrl = 'http://' + api[1] + '/bbox/?bbox=';
apiKey = api[0];
} else {
throw new Error('API auth failed');
}
topo = L.tileLayer('http://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=topo2&zoom={z}&x={x}&y={y}', {
maxZoom: 16,
attribution: '<a href="http://www.statkart.no/">Statens kartverk</a>'
});
var summer = L.tileLayer('http://mt3.turistforeningen.no/prod/trail_summer/{z}/{x}/{y}.png', {
maxZoom: 16,
attribution: '<a href="http://www.turistforeningen.no/">DNT</a>'
});
var winter = L.tileLayer('http://mt3.turistforeningen.no/prod/trail_winter/{z}/{x}/{y}.png', {
maxZoom: 16,
attribution: '<a href="http://www.turistforeningen.no/">DNT</a>'
});
var cabin = L.tileLayer('http://mt3.turistforeningen.no/prod/cabin/{z}/{x}/{y}.png', {
maxZoom: 16,
attribution: '<a href="http://www.turistforeningen.no/">DNT</a>'
});
map = new L.Map('map', {
layers: [topo]
,center: new L.LatLng(61.5, 9)
,zoom: 13
});
cabin.addTo(map);
summer.addTo(map);
L.control.layers({'Topo 2': topo}, {
'DNTs merkede stier': summer
,'DNTs merkede vinterruter': winter
,'DNTs turisthytter': cabin
}, {
position: 'topleft'
}).addTo(map);
// Import Layer
inport = new L.layerGroup(null, {
style: {
opacity:0.5
,clickable:false
}
}).addTo(map);
// Snapping Layer
snapping = new L.geoJson(null, {
style: {
opacity:0
,clickable:false
}
}).addTo(map);
map.on('moveend', function() {
if (map.getZoom() > 12) {
var url;
url = sUrl + map.getBounds().toBBoxString() + '&callback=?';
$.getJSON(url).always(function(data, status) {
if (status === 'success') {
data = JSON.parse(data);
if (data.geometries && data.geometries.length > 0) {
snapping.clearLayers();
snapping.addData(data);
}
} else {
console.error('Could not load snapping data');
}
});
} else {
snapping.clearLayers();
}
});
map.fire('moveend');
// Routing Function
// @todo speed up geometryToLayer()
myRouter = function(l1, l2, cb) {
var req = $.getJSON(rUrl + [l1.lng, l1.lat, l2.lng, l2.lat].join(',') + '&callback=?');
req.always(function(data, status) {
if (status === 'success') {
try {
L.GeoJSON.geometryToLayer(JSON.parse(data)).eachLayer(function (layer) {
// 14026
var d1 = l1.distanceTo(layer._latlngs[0]);
var d2 = l2.distanceTo(layer._latlngs[layer._latlngs.length-1]);
if (d1 < 10 && d2 < 10) {
return cb(null, layer);
} else {
return cb(new Error('This has been discarded'));
}
});
} catch(e) {
return cb(new Error('Invalid JSON'));
}
} else {
return cb(new Error('Routing failed'));
}
});
}
// Leaflet Routing Module
routing = new L.Routing({
position: 'topleft'
,routing: {
router: myRouter
}
,snapping: {
layers: [snapping]
,sensitivity: 15
,vertexonly: false
}
});
map.addControl(routing);
routing.draw(true); // enable drawing mode
$('#eta-export').hide();
$('#eta-export').on('click', function() {
var id = $('#eta-id').val();
if (!id) { alert('Ingen tp_id definert!'); return; }
if (confirm('Eksport til ETA vil overskrive eksisterende geometri!')) {
var coords = routing.toGeoJSON().coordinates;
var data = [];
for (var i = 0; i < coords.length; i++) {
data.push(coords[i][0] + ' ' + coords[i][1]);
}
data = 'LINESTRING(' + data.join(',') + ')';
$.post('http://mintur.ut.no/lib/ajax/post_geom.php?api_key=' + apiKey + '&tp_id=' + id, {coords: data}, function(data) {
if (data.error) {
alert('Eksport feilet med feilkode ' + data.error);
} else if (data.success) {
window.location.href = 'http://mintur.ut.no/index.php?tp_id=' + id + '&tab=kart';
//alert('Eksport suksess!');
}
});
}
});
$('#eta-import').on('click', function() {
var id = $('#eta-id').val();
if (!id) { alert('Ingen tp_id definert!'); return; }
$.get('http://mintur.ut.no/lib/ajax/post_geom.php?api_key=' + apiKey + '&tp_id=' + id, function(data) {
if (data.error) {
alert('Import feilet med feilkode ' + data.error);
} else if (typeof data.coords !== 'undefined') {
$('#eta-import').hide();
$('#eta-export').show();
$('#eta-id').attr('readonly', 'readonly');
if (data.coords) {
data.coords = data.coords.replace('LINESTRING(', '').replace(')', '').split(',');
for (var i = 0; i < data.coords.length; i++) {
data.coords[i] = new L.LatLng(data.coords[i].split(' ')[1], data.coords[i].split(' ')[0]);
}
inport.clearLayers();
var p = new L.Polyline(data.coords, {clickable:false, color: '#000000', opacity: 0.4});
inport.addLayer(p);
map.fitBounds(p.getBounds());
}
}
});
});
function fetchSsrAc(search, cb) {
var result = [];
$.ajax({
url: "https://ws.geonorge.no/SKWS3Index/ssr/sok?navn=" + search + "*&epsgKode=4326&antPerSide=10"
,type: "GET"
,dataType: 'xml'
,success: function(xml) {
$(xml).find('sokRes > stedsnavn').each(function(){
result.push({
title: $(this).find('stedsnavn').text()
,lat: $(this).find('aust').text()
,lng: $(this).find('nord').text()
});
});
cb(null, result);
}
});
}
$('#ssr-search').typeahead({
remote: {
url: 'https://ws.geonorge.no/SKWS3Index/ssr/sok?navn=%QUERY*&epsgKode=4326&antPerSide=10',
dataType: 'xml',
filter: function(xml) {
var result = [];
$(xml).find('sokRes > stedsnavn').each(function(){
result.push({
value: $(this).find('stedsnavn').text()
,tokens: [$(this).find('stedsnavn').text()]
,lat: $(this).find('nord').text()
,lng: $(this).find('aust').text()
});
});
return result;
}
}
});
$('#ssr-search').on('typeahead:selected', function(e, object) {
var ll = new L.LatLng(object.lat, object.lng);
map.panTo(ll);
$('#ssr-search').val('');
})
});
}).call(this);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -1,44 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Routing in Leaflet</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="libs/leaflet/leaflet.ie.css" /><![endif]-->
<link rel="stylesheet" href="app.css" />
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-38558206-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div id="search">
<strong>Søk:</strong> <input type="text" id="ssr-search">
</div>
<div id="export">
<strong>tp_id</strong>: <input type="text" id="eta-id">
<button id="eta-export">Eksport</button>
<button id="eta-import">Import</button>
</div>
<div id="map"></div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src="src/utils/LineUtil.Snapping.js"></script>
<script src="src/utils/Marker.Snapping.js"></script>
<script src="src/L.Routing.js"></script>
<script src="src/L.Routing.Storage.js"></script>
<script src="src/L.Routing.Draw.js"></script>
<script src="src/L.Routing.Edit.js"></script>
<script src="http://twitter.github.io/typeahead.js/releases/0.9.3/typeahead.min.js"></script>
<script src="app.js"></script>
</body>
</html>

View file

@ -1,309 +0,0 @@
/*
* L.Routing.Draw class
*
* Responsible for drawing and contine drawing
*
* @dependencies L, L.Routing
*
* @usage new L.Routing.Draw(map, options);
*/
L.Routing.Draw = L.Handler.extend({
// INCLUDES
includes: [L.Mixin.Events]
// OPTIONS
,options: {}
/**
* Draw Constructor
*
* @access public
*
* @param <> parent - parent class instance
* @param <Oject> options - routing options
*
* @return void
*
* @todo fetch last waypoint
*/
,initialize: function (parent, options) {
this._parent = parent;
this._map = parent._map;
this._enabled = false;
L.Util.setOptions(this, options);
}
/**
* Enable drawing
*
* @access public
*
* @event map.routing:draw-start
* @event map.routing:draw-new
* @event map.routing:draw-continue
*
* @return void
*/
,enable: function() {
if (this._enabled) { return; }
this._enabled = true;
this._hidden = false;
this._dragging = false;
this._addHooks();
this.fire('enabled');
this._map.fire('routing:draw-start');
if (this._parent._segments._layers.length === 0) {
this._map.fire('routing:draw-new');
} else {
this._map.fire('routing:draw-continue');
}
}
/**
* Disable drawing
*
* @access public
*
* @event map.routing:draw-end
*
* @return void
*/
,disable: function() {
if (!this._enabled) { return; }
this._enabled = false;
this._removeHooks();
this.fire('disabled');
this._map.fire('routing:draw-end');
}
/**
* Add hooks
*
* @access private
*
* @return void
*/
,_addHooks: function() {
if (!this._map) { return; }
// Visible Marker
if (!this._marker) {
this._marker = new L.Marker(this._map.getCenter(), {
icon: (this.options.icons.draw ? this.options.icons.draw : new L.Icon.Default())
,opacity: (this.options.icons.draw ? 1.0 : 0.0)
,zIndexOffset: this.options.zIndexOffset
,clickable: false
});
}
// Trailing line
if (!this._trailer) {
var ll = this._map.getCenter();
this._trailerOpacity = this.options.styles.trailer.opacity || 0.2;
var style = L.extend({}, this.options.styles.trailer, {
opacity: 0.0
,clickable: false
});
this._trailer = new L.Polyline([ll, ll], style);
}
this._parent.on('waypoint:mouseover', this._catchWaypointEvent, this);
this._parent.on('waypoint:mouseout' , this._catchWaypointEvent, this);
this._parent.on('waypoint:dragstart', this._catchWaypointEvent, this);
this._parent.on('waypoint:dragend' , this._catchWaypointEvent, this);
this._parent.on('segment:mouseover' , this._catchWaypointEvent, this);
this._parent.on('segment:mouseout' , this._catchWaypointEvent, this);
this._parent.on('segment:dragstart' , this._catchWaypointEvent, this);
this._parent.on('segment:dragend' , this._catchWaypointEvent, this);
this._map.on('mousemove', this._onMouseMove, this);
this._map.on('click', this._onMouseClick, this);
this._marker.addTo(this._map);
this._trailer.addTo(this._map);
}
/**
* Remove hooks
*
* This method is invoked after the `disable()` has been called and removes
* all the hooks set up using the `_addHooks()` method.
*
* @access private
*
* @return void
*/
,_removeHooks: function() {
if (!this._map) { return; }
this._parent.off('waypoint:mouseover', this._catchWaypointEvent, this);
this._parent.off('waypoint:mouseout' , this._catchWaypointEvent, this);
this._parent.off('waypoint:dragstart', this._catchWaypointEvent, this);
this._parent.off('waypoint:dragend' , this._catchWaypointEvent, this);
this._parent.off('segment:mouseover' , this._catchWaypointEvent, this);
this._parent.off('segment:mouseout' , this._catchWaypointEvent, this);
this._parent.off('segment:dragstart' , this._catchWaypointEvent, this);
this._parent.off('segment:dragend' , this._catchWaypointEvent, this);
this._map.off('click', this._onMouseClick, this);
this._map.off('mousemove', this._onMouseMove, this);
this._map.removeLayer(this._marker);
this._map.removeLayer(this._trailer);
delete this._marker;
delete this._trailer;
}
/**
* Handle waypoint events
*
* @access private
*
* @param <L.Event> e - waypoint event
*
* @return void
*/
,_catchWaypointEvent: function(e) {
var type = e.type.split(':')[1];
if (this._hidden) {
if (this._dragging) {
if (type === 'dragend') {
this._dragging = false;
}
} else {
if (type === 'mouseout') {
this._show();
} else if (type === 'dragstart') {
this._dragging = true;
}
}
} else {
if (type === 'mouseover') {
this._hide();
}
}
}
/**
* Hide HUD
*
* Call this method in order to quickly hide graphical drawing elements for
* instance hoovering over draggable objects which should tempoarily disable
* dragging.
*
* @access private
*
* @return void
*/
,_hide: function() {
this._hidden = true;
this._marker.setOpacity(0.0);
this._trailer.setStyle({opacity: 0.0});
}
/**
* Show HUD
*
* Call this method to restore graphical drawing elements after they have been
* hidden.
*
* @access private
*
* @return void
*/
,_show: function() {
this._hidden = false;
this._marker.setOpacity(this.options.icons.draw ? 1.0 : 0.0);
this._showTrailer();
}
/**
* Show trailer when hidden
*
* @access private
*
* @return void
*/
,_showTrailer: function() {
if (this._trailer.options.opacity === 0.0) {
this._trailer.setStyle({opacity: this._trailerOpacity});
}
}
/**
* Set trailing guide line
*
*/
,_setTrailer: function(fromLatLng, toLatLng) {
this._trailer.setLatLngs([fromLatLng, toLatLng]);
this._showTrailer();
}
/**
* Mouse move handler
*
* @access private
*
* @param <L.Event> e - mouse move event
*
* @return void
*/
,_onMouseMove : function(e) {
if (this._hidden) { return; }
var latlng = e.latlng;
var last = this._parent.getLast();
if (this.options.snapping) {
latlng = L.LineUtil.snapToLayers(latlng, null, this.options.snapping);
}
this._marker.setLatLng(latlng);
if (last !== null) {
this._setTrailer(last.getLatLng(), latlng);
};
}
/**
* Mouse click handler
*
* @access private
*
* @param <L.Event> e - mouse click event
*
* @event map.routing:new-waypoint
*
* @return void
*/
,_onMouseClick: function(e) {
if (this._hidden) { return; }
var marker, latlng, last;
latlng = e.latlng;
if (this.options.snapping) {
latlng = L.LineUtil.snapToLayers(latlng, null, this.options.snapping);
}
marker = new L.Marker(latlng, {title: this.options.tooltips.waypoint });
last = this._parent.getLast();
this._setTrailer(latlng, latlng);
this._parent.addWaypoint(marker, last, null, function(err, data) {
// console.log(err, data);
});
}
});

View file

@ -1,389 +0,0 @@
/*
* L.Routing.Edit class
*
* Responsible handle edits
*
* @dependencies L, L.Routing
*
* @usage new L.Routing.Draw(map, options);
*/
L.Routing.Edit = L.Handler.extend({
// INCLUDES
includes: [L.Mixin.Events]
// OPTIONS
,options: {}
/**
* Edit Constructor
*
* @access public
*
* @param <> parent - parent class instance
* @param <Oject> options - routing options
*
* @return void
*
* @todo fetch last waypoint
*/
,initialize: function (parent, options) {
this._parent = parent;
this._map = parent._map;
this._enabled = false;
L.Util.setOptions(this, options);
}
/**
* Enable drawing
*
* @access public
*
* @event map.routing:edit-start
*
* @return void
*/
,enable: function() {
if (this._enabled) { return; }
this._enabled = true;
this._addHooks();
this.fire('enabled');
this._map.fire('routing:edit-start');
}
/**
* Disable drawing
*
* @access public
*
* @event map.draw:edit-end
*
* @return void
*/
,disable: function() {
if (!this._enabled) { return; }
this._enabled = false;
this._removeHooks();
this.fire('disabled');
this._map.fire('routing:edit-end');
}
/**
* Add hooks
*
* This method is invoked when `enable()` is called and sets up all
* necessary hooks such as:
* * text selection
* * key listeners
* * mouse marker
*
* @access private
*
* @return void
*
* @todo hide and style the trailer!
*/
,_addHooks: function() {
if (!this._map) { return; }
if (!this._mouseMarker) {
this._mouseMarker = new L.Marker(this._map.getCenter(), {
icon: L.divIcon({
className: 'line-mouse-marker'
,iconAnchor: [5, 5]
,iconSize: [10, 10]
})
,clickable: true
,draggable: true
,opacity: 0
,zIndexOffset: this.options.zIndexOffset
,title: this.options.tooltips.segment
});
}
this._mouseMarker.addTo(this._map);
if (!this._trailer1) {
var ll = this._map.getCenter();
this._trailerOpacity = this.options.styles.trailer.opacity || 0.2;
var style = L.extend({}, this.options.styles.trailer, {opacity: 0.0,clickable: false});
this._trailer1 = new L.Polyline([ll, ll], style);
this._trailer2 = new L.Polyline([ll, ll], style);
}
this._trailer1.addTo(this._map);
this._trailer2.addTo(this._map);
this._parent.on('segment:mouseover' , this._segmentOnMouseover, this);
this._mouseMarker.on('dragstart' , this._segmentOnDragstart, this);
this._mouseMarker.on('drag' , this._segmentOnDrag, this);
this._mouseMarker.on('dragend' , this._segmentOnDragend, this);
this._parent.on('waypoint:dragstart', this._waypointOnDragstart, this);
this._parent.on('waypoint:drag' , this._waypointOnDrag, this);
this._parent.on('waypoint:dragend' , this._waypointOnDragend, this);
}
/**
* Remove hooks
*
* This method is invoked after the `disable()` has been called and removes
* all the hooks set up using the `_addHooks()` method.
*
* @access private
*
* @return void
*/
,_removeHooks: function() {
if (!this._map) { return; }
// this._trailer1.addTo(this._map);
// this._trailer2.addTo(this._map);
this._parent.off('segment:mouseover' , this._segmentOnMouseover, this);
this._mouseMarker.off('dragstart' , this._segmentOnDragstart, this);
this._mouseMarker.off('drag' , this._segmentOnDrag, this);
this._mouseMarker.off('dragend' , this._segmentOnDragend, this);
this._parent.off('waypoint:dragstart', this._waypointOnDragstart, this);
this._parent.off('waypoint:drag' , this._waypointOnDrag, this);
this._parent.off('waypoint:dragend' , this._waypointOnDragend, this);
}
/**
* Fired when the mouse first enters a segment
*
* @access private
*
* @param <L.Event> e - mouse over event
*
* @return void
*/
,_segmentOnMouseover: function(e) {
this._mouseMarker.setOpacity(1.0);
this._map.on('mousemove', this._segmentOnMousemove, this);
}
/**
* Fired when the mouse leaves a segement
*
* @access private
*
* @param <L.Event> e - mouse move event
*
* @return void
*/
,_segmentOnMouseout: function(e) {
if (this._dragging) { return; }
this._mouseMarker.setOpacity(0.0);
this._map.off('mousemove', this._segmentOnMousemove, this);
this.fire('segment:mouseout');
}
/**
* Fired when the mouse is moved
*
* This method is fired continously when mouse is moved in edition mode.
*
* @access private
*
* @param <L.Event> e - mouse move event
*
* @return void
*/
,_segmentOnMousemove: function(e) {
if (this._dragging) { return; }
var latlng = L.LineUtil.snapToLayers(e.latlng, null, {
layers: [this._parent._segments]
,sensitivity: 40
,vertexonly: false
});
if (latlng._feature === null) {
this._segmentOnMouseout(e);
} else {
this._mouseMarker._snapping = latlng._feature._routing;
this._mouseMarker.setLatLng(latlng);
}
}
/**
* Mouse marker dragstart
*
* @access private
*
* @param <L.Event> e - mouse dragstart event
*
* @return void
*/
,_segmentOnDragstart: function(e) {
var latlng = e.target.getLatLng();
var next = e.target._snapping.nextMarker;
var prev = e.target._snapping.prevMarker;
this._setTrailers(latlng, next, prev, true);
this._dragging = true;
this.fire('segment:dragstart');
}
/**
* Fired when a marker is dragged
*
* This method is fired continously when dragging a marker and snapps the
* marker to the snapping layer.
*
* @access private
*
* @param <L.Event> e - mouse drag event
*
* @return void
*/
,_segmentOnDrag: function(e) {
var latlng = e.target.getLatLng();
var next = e.target._snapping.nextMarker;
var prev = e.target._snapping.prevMarker;
if (this.options.snapping) {
latlng = L.LineUtil.snapToLayers(latlng, null, this.options.snapping);
}
e.target.setLatLng(latlng);
this._setTrailers(latlng, next, prev);
}
/**
* Mouse marker dragend
*
* @access private
*
* @param <L.Event> e - mouse dragend event
*
* @return void
*/
,_segmentOnDragend: function(e) {
var next = this._mouseMarker._snapping.nextMarker;
var prev = this._mouseMarker._snapping.prevMarker;
var latlng = this._mouseMarker.getLatLng();
this._parent.addWaypoint(latlng, prev, next, function(err, data) {
//console.log(err, data);
});
this._dragging = false;
this._setTrailers(null, null, null, false);
this.fire('segment:dragend');
}
/**
* Fired when marker drag start
*
* @access private
*
* @param <L.Event> e - mouse dragend event
*
* @return void
*/
,_waypointOnDragstart: function(e) {
var next = e.marker._routing.nextMarker;
var prev = e.marker._routing.prevMarker;
this._setTrailers(e.marker.getLatLng(), next, prev, true);
}
/**
* Fired while dragging marker
*
* @access private
*
* @access private
*
* @param <L.Event> e - mouse drag event
*
* @return void
*/
,_waypointOnDrag: function(e) {
var latlng = e.marker._latlng;
var next = e.marker._routing.nextMarker;
var prev = e.marker._routing.prevMarker;
if (this.options.snapping) {
latlng = L.LineUtil.snapToLayers(latlng, null, this.options.snapping);
}
e.marker.setLatLng(latlng);
this._setTrailers(latlng, next, prev);
}
/**
* Fired when marker drag ends
*
* @access private
*
* @param <L.Event> e - mouse dragend event
*
* @return void
*/
,_waypointOnDragend: function(e) {
this._setTrailers(null, null, null, false);
this._parent.routeWaypoint(e.marker, function(err, data) {
//console.log('_waypointOnDragend.cb', err, data);
});
}
/**
* Fired when marker is clicked
*
* This method is fired when a marker is clicked by the user. It will then
* procede to remove the marker and reroute any connected line segments.
*
* @access private
*
* @param <L.Event> e - mouse click event
*
* @return void
*/
,_waypointOnClick: function(e) {
this._parent.removeWaypoint(e.layer, function(err, data) {
//console.log('_waypointOnDragend.cb', err, data);
});
}
/**
* Set trailing guide lines
*
*/
,_setTrailers: function(latlng, next, prev, show) {
if (typeof show !== 'undefined') {
if (show === false) {
this._trailer1.setStyle({opacity: 0.0});
this._trailer2.setStyle({opacity: 0.0});
return;
} else {
if (next !== null) {
this._trailer1.setStyle({opacity: this._trailerOpacity});
}
if (prev !== null) {
this._trailer2.setStyle({opacity: this._trailerOpacity});
}
}
}
if (next) {
this._trailer1.setLatLngs([latlng, next.getLatLng()]);
}
if (prev) {
this._trailer2.setLatLngs([latlng, prev.getLatLng()]);
}
}
});

View file

@ -1,31 +0,0 @@
/*
* Leaflet Routing Storage
*
* Storing routable objects
*
* @dependencies L, L.Routing
*
* @usage new L.Routing(options);
*/
(function () {
L.Routing.Storage = L.MultiPolyline.extend({
/**
* Class constructor
*/
initialize: function (latlngs, options) {
this._layers = {};
this._options = options;
this.setLatLngs(latlngs);
this.on('layeradd', function() {
console.log('layeradd', arguments);
}, this);
}
});
L.Routing.storage = function (latlngs, options) {
return new L.MultiPolyline(latlngs, options);
};
}());

View file

@ -1,723 +0,0 @@
/*
* L.Routing main class
*
* Main clase for the Leaflet routing module
*
* @dependencies L
*
* @usage new L.Routing(options);
*
* @todo use L.Class.extend instead?
*/
L.Routing = L.Control.extend({
// INCLUDES
includes: [L.Mixin.Events]
// CONSTANTS
,statics: {
VERSION: '0.1.1-dev'
}
// OPTIONS
,options: {
position: 'topleft'
,tooltips: {
waypoint: 'Waypoint. Drag to move; Click to remove.',
segment: 'Drag to create a new waypoint'
}
,icons: {
start: new L.Icon.Default()
,end: new L.Icon.Default()
,normal: new L.Icon.Default()
,draw: new L.Icon.Default()
}
,styles: {
trailer: {}
,track: {}
,nodata: {}
}
,zIndexOffset: 2000
,routing: {
router: null // function (<L.Latlng> l1, <L.Latlng> l2, <Function> cb)
}
,snapping: {
layers: [] // layers to snap to
,sensitivity: 10 // snapping sensitivity
,vertexonly: false // vertex only snapping
}
,shortcut: {
draw: {
enable: 68, // char code for 'd'
disable: 81 // char code for 'q'
}
}
}
/**
* Routing Constructor
*
* @access public
*
* @param <Object> options - non-default options
*
* @todo render display of segments and waypoints
*/
,initialize: function (options) {
this._editing = false;
this._drawing = false;
L.Util.setOptions(this, options);
}
/**
* Called when controller is added to map
*
* @access public
*
* @param <L.Map> map - map instance
*
* @return <HTMLElement> container
*/
,onAdd: function (map) {
this._map = map;
this._container = this._map._container;
this._overlayPane = this._map._panes.overlayPane;
this._popupPane = this._map._panes.popupPane;
this._router = this.options.routing.router;
this._segments = new L.FeatureGroup().addTo(map);
this._waypoints = new L.FeatureGroup().addTo(map);
this._waypoints._first = null;
this._waypoints._last = null;
//L.DomUtil.disableTextSelection();
//this._tooltip = new L.Tooltip(this._map);
//this._tooltip.updateContent({ text: L.drawLocal.draw.marker.tooltip.start });
if (this.options.shortcut) {
L.DomEvent.addListener(this._container, 'keyup', this._keyupListener, this);
}
this._draw = new L.Routing.Draw(this, this.options);
this._edit = new L.Routing.Edit(this, this.options);
this._edit.enable();
this.on('waypoint:click', this._waypointClickHandler, this)
this._segments.on('mouseover' , this._fireSegmentEvent, this);
this._edit.on('segment:mouseout' , this._fireSegmentEvent, this);
this._edit.on('segment:dragstart', this._fireSegmentEvent, this);
this._edit.on('segment:dragend' , this._fireSegmentEvent, this);
var container = L.DomUtil.create('div', 'leaflet-routing');
return container;
}
/**
* Called when controller is removed from map
*
* @access public
*
* @param <L.Map> map - map instance
*/
,onRemove: function(map) {
//L.DomUtil.create('div', 'leaflet-routing'); <= delete this
this.off('waypoint:click', this._waypointClickHandler, this)
this._segments.off('mouseover' , this._fireSegmentEvent, this);
this._edit.off('segment:mouseout' , this._fireSegmentEvent, this);
this._edit.off('segment:dragstart', this._fireSegmentEvent, this);
this._edit.off('segment:dragend' , this._fireSegmentEvent, this);
this._edit.disable();
this._draw.disable();
L.DomUtil.enableTextSelection();
// this._tooltip.dispose();
// this._tooltip = null;
L.DomEvent.removeListener(this._container, 'keyup', this._keyupListener);
delete this._draw;
delete this._edit;
delete this._map;
delete this._router;
delete this._segments;
delete this._waypoints;
delete this.options;
}
/**
* Called whenever a waypoint is clicked
*
* @access private
*
* @param <L.Event> e - click event
*/
,_waypointClickHandler: function(e) {
this.removeWaypoint(e.marker, function() {
// console.log(arguments);
});
}
/**
* Add new waypoint to path
*
* @access public
*
* @param <L.Marker> marker - new waypoint marker (can be ll)
* @param <L.Marker> prev - previous waypoint marker
* @param <L.Marker> next - next waypoint marker
* @param <Function> cb - callback method (err, marker)
*
* @return void
*/
,addWaypoint: function(marker, prev, next, cb) {
if (marker instanceof L.LatLng) {
marker = new L.Marker(marker, { title: this.options.tooltips.waypoint });
}
marker._routing = {
prevMarker : prev
,nextMarker : next
,prevLine : null
,nextLine : null
,timeoutID : null
};
if (this._waypoints._first === null && this._waypoints._last === null) {
this._waypoints._first = marker;
this._waypoints._last = marker;
} else if (next === null) {
this._waypoints._last = marker;
} else if (prev === null) {
this._waypoints._first = marker;
}
if (marker._routing.prevMarker !== null) {
marker._routing.prevMarker._routing.nextMarker = marker;
marker._routing.prevLine = marker._routing.prevMarker._routing.nextLine;
if (marker._routing.prevLine !== null) {
marker._routing.prevLine._routing.nextMarker = marker;
}
}
if (marker._routing.nextMarker !== null) {
marker._routing.nextMarker._routing.prevMarker = marker;
marker.nextLine = marker._routing.nextMarker._routing.prevLine;
if (marker._routing.nextLine !== null) {
marker._routing.nextLine._routing.prevMarker = marker;
}
}
marker.on('mouseover', this._fireWaypointEvent, this);
marker.on('mouseout' , this._fireWaypointEvent, this);
marker.on('dragstart', this._fireWaypointEvent, this);
marker.on('dragend' , this._fireWaypointEvent, this);
marker.on('drag' , this._fireWaypointEvent, this);
marker.on('click' , this._fireWaypointEvent, this);
this.routeWaypoint(marker, cb);
this._waypoints.addLayer(marker);
marker.dragging.enable();
}
/**
* Remove a waypoint from path
*
* @access public
*
* @param <L.Marker> marker - new waypoint marker (can be ll)
* @param <Function> cb - callback method
*
* @return void
*/
,removeWaypoint: function(marker, cb) {
marker.off('mouseover', this._fireWaypointEvent, this);
marker.off('mouseout' , this._fireWaypointEvent, this);
marker.off('dragstart', this._fireWaypointEvent, this);
marker.off('dragend' , this._fireWaypointEvent, this);
marker.off('drag' , this._fireWaypointEvent, this);
marker.off('click' , this._fireWaypointEvent, this);
var prev = marker._routing.prevMarker;
var next = marker._routing.nextMarker;
if (this._waypoints._first && marker._leaflet_id === this._waypoints._first._leaflet_id) {
this._waypoints._first = next;
}
if (this._waypoints._last && marker._leaflet_id === this._waypoints._last._leaflet_id) {
this._waypoints._last = prev;
}
if (prev !== null) {
prev._routing.nextMarker = next;
prev._routing.nextLine = null;
}
if (next !== null) {
next._routing.prevMarker = prev;
next._routing.prevLine = null;
}
if (marker._routing.nextLine !== null) {
this._segments.removeLayer(marker._routing.nextLine);
}
if (marker._routing.prevLine !== null) {
this._segments.removeLayer(marker._routing.prevLine);
}
this._waypoints.removeLayer(marker);
if (prev !== null) {
this.routeWaypoint(prev, cb);
} else if (next !== null) {
this.routeWaypoint(next, cb);
} else {
this._draw.enable();
cb(null, null);
}
}
/**
* Route with respect to waypoint
*
* @access public
*
* @param <L.Marker> marker - marker to route on
* @param <Function> cb - callback function
*
* @return void
*
* @todo add propper error checking for callback
*/
,routeWaypoint: function(marker, cb) {
var i = 0;
var firstErr;
var $this = this;
var callback = function(err, data) {
i++;
firstErr = firstErr || err;
if (i === 2) {
$this.fire('routing:routeWaypointEnd', { err: firstErr });
cb(firstErr, marker);
}
}
this.fire('routing:routeWaypointStart');
this._routeSegment(marker._routing.prevMarker, marker, callback);
this._routeSegment(marker, marker._routing.nextMarker, callback);
}
/**
* Recalculate the complete route by routing each segment
*
* @access public
*
* @param <Function> cb - callback function
*
* @return void
*
* @todo add propper error checking for callback
*/
,rerouteAllSegments: function(cb) {
var numSegments = this.getWaypoints().length - 1;
var callbackCount = 0;
var firstErr;
var $this = this;
var callback = function(err, data) {
callbackCount++;
firstErr = firstErr || err;
if (callbackCount >= numSegments) {
$this.fire('routing:rerouteAllSegmentsEnd', { err: firstErr });
if (cb) {
cb(firstErr);
}
}
};
$this.fire('routing:rerouteAllSegmentsStart');
if (numSegments < 1) {
return callback(null, true);
}
this._eachSegment(function(m1, m2) {
this._routeSegment(m1, m2, callback);
});
}
/**
* Route segment between two markers
*
* @access private
*
* @param <L.Marker> m1 - first waypoint marker
* @param <L.Marker> m2 - second waypoint marker
* @param <Function> cb - callback function (<Error> err, <String> data)
*
* @return void
*
* @todo logic if router fails
*/
,_routeSegment: function(m1, m2, cb) {
var $this = this;
if (m1 === null || m2 === null) {
return cb(null, true);
}
this._router(m1.getLatLng(), m2.getLatLng(), function(err, layer) {
if (typeof layer === 'undefined') {
var layer = new L.Polyline([m1.getLatLng(), m2.getLatLng()], $this.options.styles.nodata);
} else {
layer.setStyle($this.options.styles.track);
}
layer._routing = {
prevMarker: m1
,nextMarker: m2
};
if (m1._routing.nextLine !== null) {
$this._segments.removeLayer(m1._routing.nextLine);
}
$this._segments.addLayer(layer);
m1._routing.nextLine = layer;
m2._routing.prevLine = layer;
return cb(err, layer);
});
}
/**
* Iterate over all segments and execute callback for each segment
*
* @access private
*
* @param <function> callback - function to call for each segment
* @param <object> context - callback execution context (this). Optional, default: this
*
* @return void
*/
,_eachSegment: function(callback, context) {
var thisArg = context || this;
var marker = this.getFirst();
if (marker === null) { return; }
while (marker._routing.nextMarker !== null) {
var m1 = marker;
var m2 = marker._routing.nextMarker;
var line = marker._routing.nextLine;
callback.call(thisArg, m1, m2, line);
marker = marker._routing.nextMarker;
}
}
/**
* Fire events
*
* @access private
*
* @param <L.Event> e - mouse event
*
* @return void
*/
,_fireWaypointEvent: function(e) {
this.fire('waypoint:' + e.type, {marker:e.target});
}
/**
*
*/
,_fireSegmentEvent: function(e) {
if (e.type.split(':').length === 2) {
this.fire(e.type);
} else {
this.fire('segment:' + e.type);
}
}
/**
* Get first waypoint
*
* @access public
*
* @return L.Marker
*/
,getFirst: function() {
return this._waypoints._first;
}
/**
* Get last waypoint
*
* @access public
*
* @return L.Marker
*/
,getLast: function() {
return this._waypoints._last;
}
/**
* Get all waypoints
*
* @access public
*
* @return <L.LatLng[]> all waypoints or empty array if none
*/
,getWaypoints: function() {
var latLngs = [];
this._eachSegment(function(m1) {
latLngs.push(m1.getLatLng());
});
if (this.getLast()) {
latLngs.push(this.getLast().getLatLng());
}
return latLngs;
}
/**
* Concatenates all route segments to a single polyline
*
* @access public
*
* @return <L.Polyline> polyline, with empty _latlngs when no route segments
*/
,toPolyline: function() {
var latLngs = [];
this._eachSegment(function(m1, m2, line) {
latLngs = latLngs.concat(line.getLatLngs());
});
return L.polyline(latLngs);
}
/**
* Export route to GeoJSON
*
* @access public
*
* @param <boolean> enforce2d - enforce 2DGeoJSON
*
* @return <object> GeoJSON object
*
*/
,toGeoJSON: function(enforce2d) {
var geojson = {type: "LineString", properties: {waypoints: []}, coordinates: []};
var current = this._waypoints._first;
if (current === null) { return geojson; }
// First waypoint marker
geojson.properties.waypoints.push({
coordinates: [current.getLatLng().lng, current.getLatLng().lat],
_index: 0
});
while (current._routing.nextMarker) {
var next = current._routing.nextMarker;
// Line segment
var tmp = current._routing.nextLine.getLatLngs();
for (var i = 0; i < tmp.length; i++) {
if (tmp[i].alt && (typeof enforce2d === 'undefined' || enforce2d === false)) {
geojson.coordinates.push([tmp[i].lng, tmp[i].lat, tmp[i].alt]);
} else {
geojson.coordinates.push([tmp[i].lng, tmp[i].lat]);
}
}
// Waypoint marker
geojson.properties.waypoints.push({
coordinates: [next.getLatLng().lng, next.getLatLng().lat],
_index: geojson.coordinates.length-1
});
// Next waypoint marker
current = current._routing.nextMarker;
}
return geojson
}
/**
* Import route from GeoJSON
*
* @access public
*
* @param <object> geojson - GeoJSON object with waypoints
* @param <object> opts - parsing options
* @param <function> cb - callback method (err)
*
* @return undefined
*
*/
,loadGeoJSON: function(geojson, opts, cb) {
var $this, oldRouter, index, waypoints;
$this = this;
// Check for optional options parameter
if (typeof opts === 'function' || typeof opts === 'undefined') {
cb = opts;
opts = {}
}
// Set default options
opts.waypointDistance = opts.waypointDistance || 50;
opts.fitBounds = opts.fitBounds || true;
// Check for waypoints before processing geojson
if (!geojson.properties || !geojson.properties.waypoints) {
if (!geojson.properties) { geojson.properties = {} };
geojson.properties.waypoints = [];
for (var i = 0; i < geojson.coordinates.length; i = i + opts.waypointDistance) {
geojson.properties.waypoints.push({
_index: i,
coordinates: geojson.coordinates[i].slice(0, 2)
});
}
if (i > geojson.coordinates.length-1) {
geojson.properties.waypoints.push({
_index: geojson.coordinates.length-1,
coordinates: geojson.coordinates[geojson.coordinates.length-1].slice(0, 2)
});
}
}
index = 0;
oldRouter = $this._router;
waypoints = geojson.properties.waypoints;
// This is a fake router.
//
// It is currently not possible to add a waypoint with a known line segment
// manually. We are hijacking the router so that we can intercept the
// request and return the correct linesegment.
//
// It you want to fix this; please make a patch and submit a pull request on
// GitHub.
$this._router = function(m1, m2, cb) { var start =
waypoints[index-1]._index; var end = waypoints[index]._index+1;
return cb(null, L.GeoJSON.geometryToLayer({
type: 'LineString',
coordinates: geojson.coordinates.slice(start, end)
}));
};
// Clean up
end = function() {
$this._router = oldRouter; // Restore router
// Set map bounds based on loaded geometry
setTimeout(function() {
if (opts.fitBounds) {
$this._map.fitBounds(L.polyline(L.GeoJSON.coordsToLatLngs(geojson.coordinates)).getBounds());
}
if (typeof cb === 'function') { cb(null); }
}, 0);
}
// Add waypoints
add = function() {
if (!waypoints[index]) { return end() }
var coords = waypoints[index].coordinates;
var prev = $this._waypoints._last;
$this.addWaypoint(L.latLng(coords[1], coords[0]), prev, null, function(err, m) {
add(++index);
});
}
add();
}
/**
* Start (or continue) drawing
*
* Call this method in order to start or continue drawing. The drawing handler
* will be activate and the user can draw on the map.
*
* @access public
*
* @return void
*
* @todo check enable
*/
,draw: function (enable) {
if (typeof enable === 'undefined') {
var enable = true;
}
if (enable) {
this._draw.enable();
} else {
this._draw.disable();
}
}
/**
* Enable or disable routing
*
* @access public
*
* @return void
*
* @todo check enable
*/
,routing: function (enable) {
throw new Error('Not implemented');
}
/**
* Enable or disable snapping
*
* @access public
*
* @return void
*
* @todo check enable
*/
,snapping: function (enable) {
throw new Error('Not implemented');
}
/**
* Key up listener
*
* * `ESC` to cancel drawing
* * `M` to enable drawing
*
* @access private
*
* @return void
*/
,_keyupListener: function (e) {
if (e.keyCode === this.options.shortcut.draw.disable) {
this._draw.disable();
} else if (e.keyCode === this.options.shortcut.draw.enable) {
this._draw.enable();
}
}
});

View file

@ -1,191 +0,0 @@
L.Util.extend(L.LineUtil, {
/**
* Snap to all layers
*
* @param <Latlng> latlng - original position
* @param <Number> id - leaflet unique id
* @param <Object> opts - snapping options
*
* @return <Latlng> closest point
*/
snapToLayers: function (latlng, id, opts) {
var i, j, keys, feature, res, sensitivity, vertexonly, layers, minDist, minPoint, map;
sensitivity = opts.sensitivity || 10;
vertexonly = opts.vertexonly || false;
layers = opts.layers || [];
minDist = Infinity;
minPoint = latlng;
minPoint._feature = null; // containing layer
if (!opts || !opts.layers || !opts.layers.length) {
return minPoint;
}
map = opts.layers[0]._map; // @todo check for undef
for (i = 0; i < opts.layers.length; i++) {
keys = Object.keys(opts.layers[i]._layers);
for (j = 0; j < keys.length; j++) {
feature = opts.layers[i]._layers[keys[j]];
// Don't even try snapping to itself!
if (id === feature._leaflet_id) { continue; }
// GeometryCollection
if (feature._layers) {
var newLatlng = this.snapToLayers(latlng, id, {
'sensitivity': sensitivity,
'vertexonly': vertexonly,
'layers': [feature]
});
// What if this is the same?
res = {'minDist': latlng.distanceTo(newLatlng), 'minPoint': newLatlng};
// Marker
} else if (feature instanceof L.Marker) {
res = this._snapToLatlngs(latlng, [feature.getLatLng()], map, sensitivity, vertexonly, minDist);
// Polyline
} else if (feature instanceof L.Polyline) {
res = this._snapToLatlngs(latlng, feature.getLatLngs(), map, sensitivity, vertexonly, minDist);
// MultiPolyline
} else if (feature instanceof L.MultiPolyline) {
console.error('Snapping to MultiPolyline is currently unsupported', feature);
res = {'minDist': minDist, 'minPoint': minPoint};
// Polygon
} else if (feature instanceof L.Polygon) {
res = this._snapToPolygon(latlng, feature, map, sensitivity, vertexonly, minDist);
// MultiPolygon
} else if (feature instanceof L.MultiPolygon) {
res = this._snapToMultiPolygon(latlng, feature, map, sensitivity, vertexonly, minDist);
// Unknown
} else {
console.error('Unsupported snapping feature', feature);
res = {'minDist': minDist, 'minPoint': minPoint};
}
if (res.minDist < minDist) {
minDist = res.minDist;
minPoint = res.minPoint;
minPoint._feature = feature;
}
}
}
return minPoint;
},
/**
* Snap to Polygon
*
* @param <Latlng> latlng - original position
* @param <L.Polygon> feature -
* @param <L.Map> map -
* @param <Number> sensitivity -
* @param <Boolean> vertexonly -
* @param <Number> minDist -
*
* @return <Object> minDist and minPoint
*/
_snapToPolygon: function (latlng, polygon, map, sensitivity, vertexonly, minDist) {
var res, keys, latlngs, i, minPoint;
minPoint = null;
latlngs = polygon.getLatLngs();
latlngs.push(latlngs[0]);
res = this._snapToLatlngs(latlng, polygon.getLatLngs(), map, sensitivity, vertexonly, minDist);
if (res.minDist < minDist) {
minDist = res.minDist;
minPoint = res.minPoint;
}
keys = Object.keys(polygon._holes);
for (i = 0; i < keys.length; i++) {
latlngs = polygon._holes[keys[i]];
latlngs.push(latlngs[0]);
res = this._snapToLatlngs(latlng, polygon._holes[keys[i]], map, sensitivity, vertexonly, minDist);
if (res.minDist < minDist) {
minDist = res.minDist;
minPoint = res.minPoint;
}
}
return {'minDist': minDist, 'minPoint': minPoint};
},
/**
* Snap to MultiPolygon
*
* @param <Latlng> latlng - original position
* @param <L.Polygon> feature -
* @param <L.Map> map -
* @param <Number> sensitivity -
* @param <Boolean> vertexonly -
* @param <Number> minDist -
*
* @return <Object> minDist and minPoint
*/
_snapToMultiPolygon: function (latlng, multipolygon, map, sensitivity, vertexonly, minDist) {
var i, keys, res, minPoint;
minPoint = null;
keys = Object.keys(multipolygon._layers);
for (i = 0; i < keys.length; i++) {
res = this._snapToPolygon(latlng, multipolygon._layers[keys[i]], map, sensitivity, vertexonly, minDist);
if (res.minDist < minDist) {
minDist = res.minDist;
minPoint = res.minPoint;
}
}
return {'minDist': minDist, 'minPoint': minPoint};
},
/**
* Snap to <Array> of <Latlang>
*
* @param <LatLng> latlng - cursor click
* @param <Array> latlngs - array of <L.LatLngs> to snap to
* @param <Object> opts - snapping options
* @param <Boolean> isPolygon - if feature is a polygon
*
* @return <Object> minDist and minPoint
*/
_snapToLatlngs: function (latlng, latlngs, map, sensitivity, vertexonly, minDist) {
var i, tmpDist, minPoint, p, p1, p2, d2;
p = map.latLngToLayerPoint(latlng);
p1 = minPoint = null;
for (i = 0; i < latlngs.length; i++) {
p2 = map.latLngToLayerPoint(latlngs[i]);
if (!vertexonly && p1 !== null) {
tmpDist = L.LineUtil.pointToSegmentDistance(p, p1, p2);
if (tmpDist < minDist && tmpDist <= sensitivity) {
minDist = tmpDist;
minPoint = map.layerPointToLatLng(L.LineUtil.closestPointOnSegment(p, p1, p2));
}
} else if ((d2 = p.distanceTo(p2)) && d2 <= sensitivity && d2 < minDist) {
minDist = d2;
minPoint = latlngs[i];
}
p1 = p2;
}
return {'minDist': minDist, 'minPoint': minPoint};
}
});

View file

@ -1,12 +0,0 @@
L.Marker.include({
/**
* Snap to function
*
* @param <LatLng> latlng - original position
*
* @return <LatLng> - new position
*/
snapTo: function (latlng) {
return L.LineUtil.snapToLayers(latlng, this._leaflet_id, this.options.snapping);
}
});

View file

@ -1,12 +0,0 @@
L.Polyline.include({
/**
* Snap to function
*
* @param <LatLng> latlng - original position
*
* @return <LatLng> - new position
*/
snapTo: function (latlng) {
return L.LineUtil.snapToLayers(latlng, this._leaflet_id, this.options.snapping);
}
});

View file

@ -1,22 +0,0 @@
{
"name": "leaflet-search",
"version": "1.5.1",
"main": "leaflet-search.js",
"ignore": [
"**/.*",
"node_modules",
"components",
"bower_components",
"examples"
],
"homepage": "https://github.com/stefanocudini/leaflet-search",
"_release": "1.5.1",
"_resolution": {
"type": "version",
"tag": "v1.5.1",
"commit": "75ab103b838a966692cfb6cb3dc78c3b0f306eee"
},
"_source": "git://github.com/stefanocudini/leaflet-search.git",
"_target": "*",
"_originalSource": "leaflet-search"
}

View file

@ -1,12 +0,0 @@
. option condition problem {autoCollapse: true, markerLocation: true} not show location, row 61
. option condition problem {autoCollapse:false }, row 62
. problem with jsonp/ajax when remote filter has different behavior of this._filterRecords, row 322
. _handleAutoresize Should resize max search box size when map is resized., row 616
. if collapse in _handleSubmit hide _markerLoc!, row 684
. autoCollapse option hide this._markerLoc before that visualized!!, row 714

View file

@ -1,115 +0,0 @@
'use strict';
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-todos');
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
meta: {
banner:
'/* \n'+
' * Leaflet Search Control v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> \n'+
' * \n'+
' * Copyright 2014 <%= pkg.author.name %> \n'+
' * <%= pkg.author.email %> \n'+
' * <%= pkg.author.url %> \n'+
' * \n'+
' * Licensed under the <%= pkg.license %> license. \n'+
' * \n'+
' * Demo: \n'+
' * <%= pkg.homepage %> \n'+
' * \n'+
' * Source: \n'+
' * <%= pkg.repository.url %> \n'+
' * \n'+
' */\n'
},
clean: {
dist: {
src: ['dist/*']
}
},
jshint: {
options: {
globals: {
console: true,
module: true
},
"-W099": true, //ignora tabs e space warning
"-W033": true,
"-W044": true //ignore regexp
},
files: ['src/*.js']
},
concat: {
//TODO cut out SearchMarker
options: {
banner: '<%= meta.banner %>'
},
dist: {
files: {
'dist/leaflet-search.src.js': ['src/leaflet-search.js'],
'dist/leaflet-search.src.css': ['src/leaflet-search.css'],
'dist/leaflet-search.mobile.src.css': ['src/leaflet-search.mobile.css']
}
}
},
uglify: {
options: {
banner: '<%= meta.banner %>'
},
dist: {
files: {
'dist/leaflet-search.min.js': ['dist/leaflet-search.src.js']
}
}
},
cssmin: {
combine: {
files: {
'dist/leaflet-search.min.css': ['src/leaflet-search.css'],
'dist/leaflet-search.mobile.min.css': ['src/leaflet-search.mobile.css']
}
},
options: {
banner: '<%= meta.banner %>'
},
minify: {
expand: true,
cwd: 'dist/',
files: {
'dist/leaflet-search.min.css': ['src/leaflet-search.css'],
'dist/leaflet-search.mobile.min.css': ['src/leaflet-search.mobile.css']
}
}
},
todos: {
options: { verbose: false },
TODO: ['src/*.js'],
},
watch: {
dist: {
options: { livereload: true },
files: ['src/*'],
tasks: ['clean','concat','cssmin','jshint']
}
}
});
grunt.registerTask('default', [
'clean',
'concat',
'cssmin',
'jshint',
'uglify',
'todos'
]);
};

View file

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2013 Stefano Cudini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -1,98 +0,0 @@
Leaflet.Control.Search
============
A leaflet control that search markers/features location by custom property.<br />
With ajax/jsonp autocompletion and JSON fields filter/remap
Copyright 2014 [Stefano Cudini](http://labs.easyblog.it/stefano-cudini/)
Tested in Leaflet 0.7.2
#Where
**Demo online:**
[labs.easyblog.it/maps/leaflet-search](http://labs.easyblog.it/maps/leaflet-search/)
**Source code:**
[Github](https://github.com/stefanocudini/leaflet-search)
[Bitbucket](https://bitbucket.org/zakis_/leaflet-search)
[NPM](https://npmjs.org/package/leaflet-search)
[Atmosphere](https://atmosphere.meteor.com/package/leaflet-search)
#Build
Since Version 1.4.7 this plugin support [Grunt](http://gruntjs.com/) for building process.
Therefore the deployment require [NPM](https://npmjs.org/) installed in your system.
After you've made sure to have npm working, run this in command line:
```bash
npm install
grunt
```
#Examples
(require src/leaflet-search.css)
Adding the search control to the map:
```javascript
map.addControl( new L.Control.Search({layer: searchLayer}) );
//searchLayer is a L.LayerGroup contains searched markers
```
Short way:
```javascript
var map = new L.Map('map', { searchControl: {layer: searchLayer} });
```
#Advanced Examples
Ajax request to search.php for retrieve elements locations:
```javascript
map.addControl( new L.Control.Search({url: 'search.php?q={s}'}) );
```
Request to third party JSONP service, implements Geocode Searching using OSM API:
```javascript
map.addControl( new L.Control.Search({
url: 'http://nominatim.openstreetmap.org/search?format=json&q={s}',
jsonpParam: 'json_callback',
propertyName: 'display_name',
propertyLoc: ['lat','lon']
}) );
```
Search and color features vector in GeoJSON layer:
```javascript
var searchControl = new L.Control.Search({layer: geojsonLayer, circleLocation:false});
searchControl.on('search_locationfound', function(e) {
e.layer.setStyle({fillColor: '#3f0'});
}).on('search_collapsed', function(e) {
featuresLayer.eachLayer(function(layer) {
featuresLayer.resetStyle(layer);
});
});
map.addControl(searchControl);
```
Static data source:
```
var data = [
{"loc":[41.575330,13.102411], "title":"aquamarine"},
{"loc":[41.575730,13.002411], "title":"black"},
{"loc":[41.219190,13.062145], "title":"cyan"}
];
map.addControl(new L.Control.Search({
markerLocation: true,
callData: function(text, callResponse) {
//here can use custom criteria or merge data from multiple layers
callResponse(data);
}
}) );
```

View file

@ -1,59 +0,0 @@
Tasks found in: src/leaflet-search.js
[Line: 22] [low] //TODO important! implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
[Line: 23] [low] //TODO implement can do research on multiple sources
[Line: 38] [low] //TODO add option for persist markerLoc after collapse!
[Line: 48] [low] //TODO add option collapsed, like control.layers
[Line: 53] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 57] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 60] [low] //TODO change structure of _recordsCache
[Line: 342] [low] //TODO add option for case sesitive search, also showLocation
[Line: 345] [low] //TODO use .filter or .map
[Line: 407] [low] //TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
[Line: 412] [low] //TODO remove script node after call run
[Line: 421] [low] //TODO add rnd param or randomize callback name! in recordsFromJsonp
[Line: 441] [low] //TODO add rnd param or randomize callback name! in recordsFromAjax
[Line: 504] [low] //TODO implements autype without selection(useful for mobile device)
[Line: 604] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 608] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 611] [low] //TODO change structure of _recordsCache
[Line: 662] [low] //TODO refact _handleAutoresize now is not accurate
[Line: 758] [low] //TODO showLocation: start animation after setView or panTo, maybe with map.on('moveend')...
[Line: 779] [low] //TODO add custom icon!
[Line: 787] [low] //TODO add inner circle
[Line: 843] [low] //TODO refact animate() more smooth! like this: http://goo.gl/DDlRs
[Line: 865] [low] //TODO use create event 'animateEnd' in SearchMarker
[Line: 50] [med] //FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
[Line: 51] [med] //FIXME option condition problem {autoCollapse: false }
[Line: 358] [med] //FIXME problem with jsonp/ajax when remote filter has different behavior of this._filterRecords
[Line: 731] [med] //FIXME if collapse in _handleSubmit hide _markerLoc!
[Line: 761] [med] //FIXME autoCollapse option hide this._markerLoc before that visualized!!
Tasks found in: src/leaflet-search_collapsed.js
[Line: 22] [low] //TODO important! implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
[Line: 23] [low] //TODO implement can do research on multiple sources
[Line: 37] [low] //TODO add option for persist markerLoc after collapse!
[Line: 47] [low] //TODO add option collapsed, like control.layers
[Line: 52] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 56] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 59] [low] //TODO change structure of _recordsCache
[Line: 87] [low] // TODO: touch
[Line: 358] [low] //TODO add option for case sesitive search, also showLocation
[Line: 361] [low] //TODO use .filter or .map
[Line: 423] [low] //TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
[Line: 428] [low] //TODO remove script node after call run
[Line: 437] [low] //TODO add rnd param or randomize callback name! in recordsFromJsonp
[Line: 457] [low] //TODO add rnd param or randomize callback name! in recordsFromAjax
[Line: 520] [low] //TODO implements autype without selection(useful for mobile device)
[Line: 620] [low] //TODO important optimization!!! always append data in this._recordsCache
[Line: 624] [low] //TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
[Line: 627] [low] //TODO change structure of _recordsCache
[Line: 678] [low] //TODO refact _handleAutoresize now is not accurate
[Line: 774] [low] //TODO showLocation: start animation after setView or panTo, maybe with map.on('moveend')...
[Line: 795] [low] //TODO add custom icon!
[Line: 803] [low] //TODO add inner circle
[Line: 859] [low] //TODO refact animate() more smooth! like this: http://goo.gl/DDlRs
[Line: 881] [low] //TODO use create event 'animateEnd' in SearchMarker
[Line: 49] [med] //FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
[Line: 50] [med] //FIXME option condition problem {autoCollapse: false }
[Line: 374] [med] //FIXME problem with jsonp/ajax when remote filter has different behavior of this._filterRecords
[Line: 747] [med] //FIXME if collapse in _handleSubmit hide _markerLoc!
[Line: 777] [med] //FIXME autoCollapse option hide this._markerLoc before that visualized!!

View file

@ -1,12 +0,0 @@
{
"name": "leaflet-search",
"version": "1.5.1",
"main": "leaflet-search.js",
"ignore": [
"**/.*",
"node_modules",
"components",
"bower_components",
"examples"
]
}

View file

@ -1,18 +0,0 @@
/*
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com
* http://labs.easyblog.it/
*
* Licensed under the MIT license.
*
* Demo:
* http://labs.easyblog.it/maps/leaflet-search/
*
* Source:
* git@github.com:stefanocudini/leaflet-search.git
*
*/
.leaflet-container .leaflet-control-search{position:relative;float:left;background:#fff;color:#1978cf;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:rgba(255,255,255,.8);z-index:1000;box-shadow:0 1px 7px rgba(0,0,0,.65);margin-left:10px;margin-top:10px}.leaflet-control-search.search-exp{box-shadow:0 1px 7px #999;background:#fff}.leaflet-control-search .search-input{display:block;float:left;background:#fff;border:1px solid #666;border-radius:2px;height:18px;padding:0 18px 0 2px;margin:3px 0 3px 3px}.leaflet-control-search.search-load .search-input{background:url(../images/loader.gif) no-repeat center right #fff}.leaflet-control-search.search-load .search-cancel{visibility:hidden}.leaflet-control-search .search-cancel{display:block;width:22px;height:18px;position:absolute;right:22px;margin:3px 0;background:url(../images/search-icon.png) no-repeat 0 -46px;text-decoration:none;filter:alpha(opacity=80);opacity:.8}.leaflet-control-search .search-cancel:hover{filter:alpha(opacity=100);opacity:1}.leaflet-control-search .search-cancel span{display:none;font-size:18px;line-height:20px;color:#ccc;font-weight:700}.leaflet-control-search .search-cancel:hover span{color:#aaa}.leaflet-control-search .search-button{display:block;float:left;width:26px;height:26px;background:url(../images/search-icon.png) no-repeat 2px 2px;border-radius:4px}.leaflet-control-search .search-button:hover{background:url(../images/search-icon.png) no-repeat 2px -22px}.leaflet-control-search .search-tooltip{position:absolute;top:100%;left:0;float:left;min-width:80px;max-height:106px;box-shadow:0 0 8px rgba(0,0,0,.4);-webkit-border-radius:5px;-webkit-border-top-left-radius:0;-moz-border-radius:5px;-moz-border-radius-topleft:0;border-radius:5px;border-top-left-radius:0;background-color:rgba(0,0,0,.25);z-index:1010;overflow-y:auto;overflow-x:hidden}.leaflet-control-search .search-tip{margin:2px;padding:2px;display:block;color:#000;background:#ddd;border-radius:.25em;text-decoration:none;white-space:nowrap;font-size:.85em;vertical-align:center}.leaflet-control-search .search-button:hover,.leaflet-control-search .search-tip-select,.leaflet-control-search .search-tip:hover{background-color:#fff}.leaflet-control-search .search-alert{cursor:pointer;clear:both;font-size:.75em;margin-bottom:5px;padding:0 .25em;color:#e00;font-weight:700;border-radius:.25em}

File diff suppressed because one or more lines are too long

View file

@ -1,18 +0,0 @@
/*
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com
* http://labs.easyblog.it/
*
* Licensed under the MIT license.
*
* Demo:
* http://labs.easyblog.it/maps/leaflet-search/
*
* Source:
* git@github.com:stefanocudini/leaflet-search.git
*
*/
.leaflet-control.leaflet-control-search{z-index:2000}.leaflet-control-search .search-input{display:block;float:left;background:#fff;border:1px solid #666;border-radius:2px;height:24px;font-size:1.25em;padding:0 .125em;margin:3px;padding-right:30px}.leaflet-control-search .search-button,.leaflet-control-search .search-button:hover{background-image:url(../images/search-icon-mobile.png);-webkit-border-radius:4px;border-radius:4px;background-position:1px 1px;width:32px;height:32px}.leaflet-control-search.search-load .search-input{background:url(../images/loader.gif) no-repeat center right #fff}.leaflet-control-search .search-cancel{background-image:url(../images/search-icon-mobile.png);-webkit-border-radius:4px;border-radius:4px;background-position:0 -62px;width:26px;height:26px;right:34px;margin:3px}.leaflet-control-search .search-tooltip{max-height:142px}.leaflet-control-search .search-tip{font-size:1em;margin:2px;padding:2px;display:block;color:#000;background:rgba(255,255,255,.8);border-radius:.25em;text-decoration:none;white-space:nowrap;vertical-align:center}.leaflet-control-search .search-tip .climbo-icon-mini{float:right;display:block;white-space:nowrap}.leaflet-control-search .search-button:hover,.leaflet-control-search .search-tip-select,.leaflet-control-search .search-tip:hover{background-color:#fff}.leaflet-control-search .search-alert{font-size:1.2em}

View file

@ -1,83 +0,0 @@
/*
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com
* http://labs.easyblog.it/
*
* Licensed under the MIT license.
*
* Demo:
* http://labs.easyblog.it/maps/leaflet-search/
*
* Source:
* git@github.com:stefanocudini/leaflet-search.git
*
*/
/* SEARCH */
.leaflet-control.leaflet-control-search {
z-index:2000;
}
.leaflet-control-search .search-input {
display:block;
float:left;
background: #fff;
border:1px solid #666;
border-radius:2px;
height:24px;
font-size:1.25em;
padding:0 .125em;
margin:3px;
padding-right:30px;
}
.leaflet-control-search .search-button:hover,
.leaflet-control-search .search-button {
background-image: url('../images/search-icon-mobile.png');
-webkit-border-radius: 4px;
border-radius: 4px;
background-position: 1px 1px;
width:32px;
height:32px;
}
.leaflet-control-search.search-load .search-input {
background: url('../images/loader.gif') no-repeat center right #fff;
}
.leaflet-control-search .search-cancel {
background-image: url('../images/search-icon-mobile.png');
-webkit-border-radius: 4px;
border-radius: 4px;
background-position: 0px -62px;
width:26px;
height:26px;
right:34px;
margin:3px;
}
.leaflet-control-search .search-tooltip {
max-height:142px;/*(.search-tip height * 5)*/
}
.leaflet-control-search .search-tip {
font-size:1em;
margin:2px;
padding:2px;
display:block;
color:black;
background: rgba(255,255,255,0.8);
border-radius:.25em;
text-decoration:none;
white-space:nowrap;
vertical-align:center;
}
.leaflet-control-search .search-tip .climbo-icon-mini {
float:right;
display:block;
white-space:nowrap;
}
.leaflet-control-search .search-button:hover,
.leaflet-control-search .search-tip-select,
.leaflet-control-search .search-tip:hover {
background-color: #fff;
}
.leaflet-control-search .search-alert {
font-size:1.2em;
}

View file

@ -1,137 +0,0 @@
/*
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com
* http://labs.easyblog.it/
*
* Licensed under the MIT license.
*
* Demo:
* http://labs.easyblog.it/maps/leaflet-search/
*
* Source:
* git@github.com:stefanocudini/leaflet-search.git
*
*/
.leaflet-container .leaflet-control-search {
position:relative;
float:left;
background:#fff;
color:#1978cf;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
background-color: rgba(255, 255, 255, 0.8);
z-index:1000;
box-shadow: 0 1px 7px rgba(0,0,0,0.65);
margin-left: 10px;
margin-top: 10px;
}
.leaflet-control-search.search-exp {/*expanded*/
box-shadow: 0 1px 7px #999;
background: #fff;
}
.leaflet-control-search .search-input {
display:block;
float:left;
background: #fff;
border:1px solid #666;
border-radius:2px;
height:18px;
padding:0 18px 0 2px;
margin:3px 0 3px 3px;
}
.leaflet-control-search.search-load .search-input {
background: url('../images/loader.gif') no-repeat center right #fff;
}
.leaflet-control-search.search-load .search-cancel {
visibility:hidden;
}
.leaflet-control-search .search-cancel {
display:block;
width:22px;
height:18px;
position:absolute;
right:22px;
margin:3px 0;
background: url('../images/search-icon.png') no-repeat 0 -46px;
text-decoration:none;
filter: alpha(opacity=80);
opacity: 0.8;
}
.leaflet-control-search .search-cancel:hover {
filter: alpha(opacity=100);
opacity: 1;
}
.leaflet-control-search .search-cancel span {
display:none;/* comment for cancel button imageless */
font-size:18px;
line-height:20px;
color:#ccc;
font-weight:bold;
}
.leaflet-control-search .search-cancel:hover span {
color:#aaa;
}
.leaflet-control-search .search-button {
display:block;
float:left;
width:26px;
height:26px;
background: url('../images/search-icon.png') no-repeat 2px 2px;
border-radius:4px;
}
.leaflet-control-search .search-button:hover {
background: url('../images/search-icon.png') no-repeat 2px -22px;
}
.leaflet-control-search .search-tooltip {
position:absolute;
top:100%;
left:0;
float:left;
min-width:80px;
max-height:106px;/*(.search-tip height * 5)*/
box-shadow: 0 0 8px rgba(0,0,0,0.4);
-webkit-border-radius: 5px;
-webkit-border-top-left-radius: 0;
-moz-border-radius: 5px;
-moz-border-radius-topleft: 0;
border-radius: 5px;
border-top-left-radius: 0;
background-color: rgba(0, 0, 0, 0.25);
z-index:1010;
overflow-y:auto;
overflow-x:hidden;
}
.leaflet-control-search .search-tip {
font-size:.85em;
margin:2px;
padding:2px;
display:block;
color:black;
background: #ddd;
border-radius:.25em;
text-decoration:none;
white-space:nowrap;
font-size:.85em;
vertical-align:center;
}
.leaflet-control-search .search-tip-select,
.leaflet-control-search .search-tip:hover,
.leaflet-control-search .search-button:hover {
background-color: #fff;
}
.leaflet-control-search .search-alert {
cursor:pointer;
clear:both;
font-size:.75em;
margin-bottom:5px;
padding:0 .25em;
color:#e00;
font-weight:bold;
border-radius:.25em;
}

View file

@ -1,901 +0,0 @@
/*
* Leaflet Search Control v1.5.1 - 2014-05-12
*
* Copyright 2014 Stefano Cudini
* stefano.cudini@gmail.com
* http://labs.easyblog.it/
*
* Licensed under the MIT license.
*
* Demo:
* http://labs.easyblog.it/maps/leaflet-search/
*
* Source:
* git@github.com:stefanocudini/leaflet-search.git
*
*/
(function() {
L.Control.Search = L.Control.extend({
includes: L.Mixin.Events,
//
// Name Data passed Description
//
//Managed Events:
// search_locationfound {latlng, title, layer} fired after moved and show markerLocation
// search_collapsed {} fired after control was collapsed
//
//Public methods:
// setLayer() L.LayerGroup() set layer search at runtime
// showAlert() 'Text message' Show alert message
//
options: {
wrapper: '', //container id to insert Search Control
url: '', //url for search by ajax request, ex: "search.php?q={s}"
jsonpParam: null, //jsonp param name for search by jsonp service, ex: "callback"
layer: null, //layer where search markers(is a L.LayerGroup)
callData: null, //function that fill _recordsCache, passed searching text by first param and callback in second
//TODO important! implements uniq option 'sourceData' that recognizes source type: url,array,callback or layer
//TODO implement can do research on multiple sources
propertyName: 'title', //property in marker.options(or feature.properties for vector layer) trough filter elements in layer,
propertyLoc: 'loc', //field for remapping location, using array: ['latname','lonname'] for select double fields(ex. ['lat','lon'] )
// support dotted format: 'prop.subprop.title'
callTip: null, //function that return row tip html node(or html string), receive text tooltip in first param
filterJSON: null, //callback for filtering data to _recordsCache
minLength: 1, //minimal text length for autocomplete
initial: true, //search elements only by initial text
autoType: true, //complete input with first suggested result and select this filled-in text.
delayType: 400, //delay while typing for show tooltip
tooltipLimit: -1, //limit max results to show in tooltip. -1 for no limit.
tipAutoSubmit: true, //auto map panTo when click on tooltip
autoResize: true, //autoresize on input change
collapsed: true, //collapse search control at startup
autoCollapse: false, //collapse search control after submit(on button or on tips if enabled tipAutoSubmit)
//TODO add option for persist markerLoc after collapse!
autoCollapseTime: 1200, //delay for autoclosing alert and collapse after blur
animateLocation: true, //animate a circle over location found
circleLocation: true, //draw a circle in location found
markerLocation: false, //draw a marker in location found
zoom: null, //zoom after pan to location found, default: map.getZoom()
text: 'Search...', //placeholder value
textCancel: 'Cancel', //title in cancel button
textErr: 'Location not found', //error message
position: 'topleft'
//TODO add option collapsed, like control.layers
},
//FIXME option condition problem {autoCollapse: true, markerLocation: true} not show location
//FIXME option condition problem {autoCollapse: false }
//
//TODO important optimization!!! always append data in this._recordsCache
// now _recordsCache content is emptied and replaced with new data founded
// always appending data on _recordsCache give the possibility of caching ajax, jsonp and layersearch!
//
//TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
// run one of callbacks search(callData,jsonpUrl or options.layer) and run this.showTooltip
//
//TODO change structure of _recordsCache
// like this: _recordsCache = {"text-key1": {loc:[lat,lng], ..other attributes.. }, {"text-key2": {loc:[lat,lng]}...}, ...}
// in this mode every record can have a free structure of attributes, only 'loc' is required
initialize: function(options) {
L.Util.setOptions(this, options || {});
this._inputMinSize = this.options.text ? this.options.text.length : 10;
this._layer = this.options.layer || new L.LayerGroup();
this._filterJSON = this.options.filterJSON || this._defaultFilterJSON;
this._autoTypeTmp = this.options.autoType; //useful for disable autoType temporarily in delete/backspace keydown
this._countertips = 0; //number of tips items
this._recordsCache = {}; //key,value table! that store locations! format: key,latlng
},
onAdd: function (map) {
this._map = map;
this._container = L.DomUtil.create('div', 'leaflet-control-search');
this._input = this._createInput(this.options.text, 'search-input');
this._tooltip = this._createTooltip('search-tooltip');
this._cancel = this._createCancel(this.options.textCancel, 'search-cancel');
this._button = this._createButton(this.options.text, 'search-button');
this._alert = this._createAlert('search-alert');
if(this.options.collapsed===false)
this.expand();
if(this.options.circleLocation || this.options.markerLocation)
this._markerLoc = new SearchMarker([0,0], {marker: this.options.markerLocation});//see below
this.setLayer( this._layer );
map.on({
// 'layeradd': this._onLayerAddRemove,
// 'layerremove': this._onLayerAddRemove
'resize': this._handleAutoresize
}, this);
return this._container;
},
addTo: function (map) {
if(this.options.wrapper) {
this._container = this.onAdd(map);
this._wrapper = L.DomUtil.get(this.options.wrapper);
this._wrapper.style.position = 'relative';
this._wrapper.appendChild(this._container);
}
else
L.Control.prototype.addTo.call(this, map);
return this;
},
onRemove: function(map) {
this._recordsCache = {};
// map.off({
// 'layeradd': this._onLayerAddRemove,
// 'layerremove': this._onLayerAddRemove
// }, this);
},
// _onLayerAddRemove: function(e) {
// //console.info('_onLayerAddRemove');
// //without this, run setLayer also for each Markers!! to optimize!
// if(e.layer instanceof L.LayerGroup)
// if( L.stamp(e.layer) != L.stamp(this._layer) )
// this.setLayer(e.layer);
// },
_getPath: function(obj, prop) {
var parts = prop.split('.'),
last = parts.pop(),
len = parts.length,
cur = parts[0],
i = 1;
if(len > 0)
while((obj = obj[cur]) && i < len)
cur = parts[i++];
if(obj)
return obj[last];
},
setLayer: function(layer) { //set search layer at runtime
//this.options.layer = layer; //setting this, run only this._recordsFromLayer()
this._layer = layer;
this._layer.addTo(this._map);
if(this._markerLoc)
this._layer.addLayer(this._markerLoc);
return this;
},
showAlert: function(text) {
text = text || this.options.textErr;
this._alert.style.display = 'block';
this._alert.innerHTML = text;
clearTimeout(this.timerAlert);
var that = this;
this.timerAlert = setTimeout(function() {
that.hideAlert();
},this.options.autoCollapseTime);
return this;
},
hideAlert: function() {
this._alert.style.display = 'none';
return this;
},
cancel: function() {
this._input.value = '';
this._handleKeypress({keyCode:8});//simulate backspace keypress
this._input.size = this._inputMinSize;
this._input.focus();
this._cancel.style.display = 'none';
return this;
},
expand: function() {
this._input.style.display = 'block';
L.DomUtil.addClass(this._container, 'search-exp');
this._input.focus();
this._map.on('dragstart', this.collapse, this);
return this;
},
collapse: function() {
this._hideTooltip();
this.cancel();
this._alert.style.display = 'none';
this._input.blur();
if(this.options.collapsed)
{
this._input.style.display = 'none';
this._cancel.style.display = 'none';
L.DomUtil.removeClass(this._container, 'search-exp');
//this._markerLoc.hide();//maybe unuseful
this._map.off('dragstart', this.collapse, this);
}
this.fire('search_collapsed');
return this;
},
collapseDelayed: function() { //collapse after delay, used on_input blur
if (!this.options.autoCollapse) return this;
var that = this;
clearTimeout(this.timerCollapse);
this.timerCollapse = setTimeout(function() {
that.collapse();
}, this.options.autoCollapseTime);
return this;
},
collapseDelayedStop: function() {
clearTimeout(this.timerCollapse);
return this;
},
////start DOM creations
_createAlert: function(className) {
var alert = L.DomUtil.create('div', className, this._container);
alert.style.display = 'none';
L.DomEvent
.on(alert, 'click', L.DomEvent.stop, this)
.on(alert, 'click', this.hideAlert, this);
return alert;
},
_createInput: function (text, className) {
var input = L.DomUtil.create('input', className, this._container);
input.type = 'text';
input.size = this._inputMinSize;
input.value = '';
input.autocomplete = 'off';
input.placeholder = text;
input.style.display = 'none';
L.DomEvent
.disableClickPropagation(input)
.on(input, 'keyup', this._handleKeypress, this)
.on(input, 'keydown', this._handleAutoresize, this)
.on(input, 'blur', this.collapseDelayed, this)
.on(input, 'focus', this.collapseDelayedStop, this);
return input;
},
_createCancel: function (title, className) {
var cancel = L.DomUtil.create('a', className, this._container);
cancel.href = '#';
cancel.title = title;
cancel.style.display = 'none';
cancel.innerHTML = "<span>&otimes;</span>";//imageless(see css)
L.DomEvent
.on(cancel, 'click', L.DomEvent.stop, this)
.on(cancel, 'click', this.cancel, this);
return cancel;
},
_createButton: function (title, className) {
var button = L.DomUtil.create('a', className, this._container);
button.href = '#';
button.title = title;
L.DomEvent
.on(button, 'click', L.DomEvent.stop, this)
.on(button, 'click', this._handleSubmit, this)
.on(button, 'focus', this.collapseDelayedStop, this)
.on(button, 'blur', this.collapseDelayed, this);
return button;
},
_createTooltip: function(className) {
var tool = L.DomUtil.create('div', className, this._container);
tool.style.display = 'none';
var that = this;
L.DomEvent
.disableClickPropagation(tool)
.on(tool, 'blur', this.collapseDelayed, this)
.on(tool, 'mousewheel', function(e) {
that.collapseDelayedStop();
L.DomEvent.stopPropagation(e);//disable zoom map
}, this)
.on(tool, 'mouseover', function(e) {
that.collapseDelayedStop();
}, this);
return tool;
},
_createTip: function(text, val) {//val is object in recordCache, usually is Latlng
var tip;
if(this.options.callTip)
{
tip = this.options.callTip(text,val); //custom tip node or html string
if(typeof tip === 'string')
{
var tmpNode = L.DomUtil.create('div');
tmpNode.innerHTML = tip;
tip = tmpNode.firstChild;
}
}
else
{
tip = L.DomUtil.create('a', '');
tip.href = '#';
tip.innerHTML = text;
}
L.DomUtil.addClass(tip, 'search-tip');
tip._text = text; //value replaced in this._input and used by _autoType
L.DomEvent
.disableClickPropagation(tip)
.on(tip, 'click', L.DomEvent.stop, this)
.on(tip, 'click', function(e) {
this._input.value = text;
this._handleAutoresize();
this._input.focus();
this._hideTooltip();
if(this.options.tipAutoSubmit)//go to location at once
this._handleSubmit();
}, this);
return tip;
},
//////end DOM creations
_filterRecords: function(text) { //Filter this._recordsCache case insensitive and much more..
var regFilter = new RegExp("^[.]$|[\[\]|()*]",'g'), //remove . * | ( ) ] [
I, regSearch,
frecords = {};
text = text.replace(regFilter,''); //sanitize text
I = this.options.initial ? '^' : ''; //search only initial text
//TODO add option for case sesitive search, also showLocation
regSearch = new RegExp(I + text,'i');
//TODO use .filter or .map
for(var key in this._recordsCache)
if( regSearch.test(key) )
frecords[key]= this._recordsCache[key];
return frecords;
},
showTooltip: function() {
var filteredRecords, newTip;
this._countertips = 0;
//FIXME problem with jsonp/ajax when remote filter has different behavior of this._filterRecords
if(this.options.layer)
filteredRecords = this._filterRecords( this._input.value );
else
filteredRecords = this._recordsCache;
this._tooltip.innerHTML = '';
this._tooltip.currentSelection = -1; //inizialized for _handleArrowSelect()
for(var key in filteredRecords)//fill tooltip
{
if(++this._countertips == this.options.tooltipLimit) break;
newTip = this._createTip(key, filteredRecords[key] );
this._tooltip.appendChild(newTip);
}
if(this._countertips > 0)
{
this._tooltip.style.display = 'block';
if(this._autoTypeTmp)
this._autoType();
this._autoTypeTmp = this.options.autoType;//reset default value
}
else
this._hideTooltip();
this._tooltip.scrollTop = 0;
return this._countertips;
},
_hideTooltip: function() {
this._tooltip.style.display = 'none';
this._tooltip.innerHTML = '';
return 0;
},
_defaultFilterJSON: function(json) { //default callback for filter data
var jsonret = {}, i,
propName = this.options.propertyName,
propLoc = this.options.propertyLoc;
if( L.Util.isArray(propLoc) )
for(i in json)
jsonret[ this._getPath(json[i],propName) ]= L.latLng( json[i][ propLoc[0] ], json[i][ propLoc[1] ] );
else
for(i in json)
jsonret[ this._getPath(json[i],propName) ]= L.latLng( this._getPath(json[i],propLoc) );
//TODO throw new Error("propertyName '"+propName+"' not found in JSON data");
return jsonret;
},
_recordsFromJsonp: function(text, callAfter) { //extract searched records from remote jsonp service
//TODO remove script node after call run
var that = this;
L.Control.Search.callJsonp = function(data) { //jsonp callback
var fdata = that._filterJSON(data);//_filterJSON defined in inizialize...
callAfter(fdata);
}
var script = L.DomUtil.create('script','search-jsonp', document.getElementsByTagName('body')[0] ),
url = L.Util.template(this.options.url+'&'+this.options.jsonpParam+'=L.Control.Search.callJsonp', {s: text}); //parsing url
//rnd = '&_='+Math.floor(Math.random()*10000);
//TODO add rnd param or randomize callback name! in recordsFromJsonp
script.type = 'text/javascript';
script.src = url;
return this;
//may be return {abort: function() { script.parentNode.removeChild(script); } };
},
_recordsFromAjax: function(text, callAfter) { //Ajax request
if (window.XMLHttpRequest === undefined) {
window.XMLHttpRequest = function() {
try { return new ActiveXObject("Microsoft.XMLHTTP.6.0"); }
catch (e1) {
try { return new ActiveXObject("Microsoft.XMLHTTP.3.0"); }
catch (e2) { throw new Error("XMLHttpRequest is not supported"); }
}
};
}
var request = new XMLHttpRequest(),
url = L.Util.template(this.options.url, {s: text}), //parsing url
//rnd = '&_='+Math.floor(Math.random()*10000);
//TODO add rnd param or randomize callback name! in recordsFromAjax
response = {};
request.open("GET", url);
var that = this;
request.onreadystatechange = function() {
if(request.readyState === 4 && request.status === 200) {
response = JSON.parse(request.responseText);
var fdata = that._filterJSON(response);//_filterJSON defined in inizialize...
callAfter(fdata);
}
};
request.send();
return this;
},
_recordsFromLayer: function() { //return table: key,value from layer
var that = this,
retRecords = {},
propName = this.options.propertyName,
loc;
this._layer.eachLayer(function(layer) {
if(layer instanceof SearchMarker) return;
if(layer instanceof L.Marker)
{
if(that._getPath(layer.options,propName))
{
loc = layer.getLatLng();
loc.layer = layer;
retRecords[ that._getPath(layer.options,propName) ] = loc;
}else if(that._getPath(layer.feature.properties,propName)){
loc = layer.getLatLng();
loc.layer = layer;
retRecords[ that._getPath(layer.feature.properties,propName) ] = loc;
}else{
console.log("propertyName '"+propName+"' not found in marker", layer);
}
}
else if(layer.hasOwnProperty('feature'))//GeoJSON layer
{
if(layer.feature.properties.hasOwnProperty(propName))
{
loc = layer.getBounds().getCenter();
loc.layer = layer;
retRecords[ layer.feature.properties[propName] ] = loc;
}
else
console.log("propertyName '"+propName+"' not found in feature", layer);
}
},this);
return retRecords;
},
_autoType: function() {
//TODO implements autype without selection(useful for mobile device)
var start = this._input.value.length,
firstRecord = this._tooltip.firstChild._text,
end = firstRecord.length;
if (firstRecord.indexOf(this._input.value) === 0) { // If prefix match
this._input.value = firstRecord;
this._handleAutoresize();
if (this._input.createTextRange) {
var selRange = this._input.createTextRange();
selRange.collapse(true);
selRange.moveStart('character', start);
selRange.moveEnd('character', end);
selRange.select();
}
else if(this._input.setSelectionRange) {
this._input.setSelectionRange(start, end);
}
else if(this._input.selectionStart) {
this._input.selectionStart = start;
this._input.selectionEnd = end;
}
}
},
_hideAutoType: function() { // deselect text:
var sel;
if ((sel = this._input.selection) && sel.empty) {
sel.empty();
}
else if (this._input.createTextRange) {
sel = this._input.createTextRange();
sel.collapse(true);
var end = this._input.value.length;
sel.moveStart('character', end);
sel.moveEnd('character', end);
sel.select();
}
else {
if (this._input.getSelection) {
this._input.getSelection().removeAllRanges();
}
this._input.selectionStart = this._input.selectionEnd;
}
},
_handleKeypress: function (e) { //run _input keyup event
switch(e.keyCode)
{
case 27: //Esc
this.collapse();
break;
case 13: //Enter
if(this._countertips == 1)
this._handleArrowSelect(1);
this._handleSubmit(); //do search
break;
case 38://Up
this._handleArrowSelect(-1);
break;
case 40://Down
this._handleArrowSelect(1);
break;
case 37://Left
case 39://Right
case 16://Shift
case 17://Ctrl
//case 32://Space
break;
case 8://backspace
case 46://delete
this._autoTypeTmp = false;//disable temporarily autoType
break;
default://All keys
if(this._input.value.length)
this._cancel.style.display = 'block';
else
this._cancel.style.display = 'none';
if(this._input.value.length >= this.options.minLength)
{
var that = this;
clearTimeout(this.timerKeypress); //cancel last search request while type in
this.timerKeypress = setTimeout(function() { //delay before request, for limit jsonp/ajax request
that._fillRecordsCache();
}, this.options.delayType);
}
else
this._hideTooltip();
}
},
_fillRecordsCache: function() {
//TODO important optimization!!! always append data in this._recordsCache
// now _recordsCache content is emptied and replaced with new data founded
// always appending data on _recordsCache give the possibility of caching ajax, jsonp and layersearch!
//
//TODO here insert function that search inputText FIRST in _recordsCache keys and if not find results..
// run one of callbacks search(callData,jsonpUrl or options.layer) and run this.showTooltip
//
//TODO change structure of _recordsCache
// like this: _recordsCache = {"text-key1": {loc:[lat,lng], ..other attributes.. }, {"text-key2": {loc:[lat,lng]}...}, ...}
// in this mode every record can have a free structure of attributes, only 'loc' is required
var inputText = this._input.value,
that;
L.DomUtil.addClass(this._container, 'search-load');
if(this.options.callData) //CUSTOM SEARCH CALLBACK
{
that = this;
this.options.callData(inputText, function(jsonraw) {
that._recordsCache = that._filterJSON(jsonraw);
that.showTooltip();
L.DomUtil.removeClass(that._container, 'search-load');
});
}
else if(this.options.url) //JSONP/AJAX REQUEST
{
if(this.options.jsonpParam)
{
that = this;
this._recordsFromJsonp(inputText, function(data) {// is async request then it need callback
that._recordsCache = data;
that.showTooltip();
L.DomUtil.removeClass(that._container, 'search-load');
});
}
else
{
that = this;
this._recordsFromAjax(inputText, function(data) {// is async request then it need callback
that._recordsCache = data;
that.showTooltip();
L.DomUtil.removeClass(that._container, 'search-load');
});
}
}
else if(this.options.layer) //SEARCH ELEMENTS IN PRELOADED LAYER
{
this._recordsCache = this._recordsFromLayer(); //fill table key,value from markers into layer
this.showTooltip();
L.DomUtil.removeClass(this._container, 'search-load');
}
},
_handleAutoresize: function() { //autoresize this._input
//TODO refact _handleAutoresize now is not accurate
if (this._input.style.maxWidth != this._map._container.offsetWidth) //If maxWidth isn't the same as when first set, reset to current Map width
this._input.style.maxWidth = L.DomUtil.getStyle(this._map._container, 'width');
if(this.options.autoResize && (this._container.offsetWidth + 45 < this._map._container.offsetWidth))
this._input.size = this._input.value.length<this._inputMinSize ? this._inputMinSize : this._input.value.length;
},
_handleArrowSelect: function(velocity) {
var searchTips = this._tooltip.hasChildNodes() ? this._tooltip.childNodes : [];
for (i=0; i<searchTips.length; i++)
L.DomUtil.removeClass(searchTips[i], 'search-tip-select');
if ((velocity == 1 ) && (this._tooltip.currentSelection >= (searchTips.length - 1))) {// If at end of list.
L.DomUtil.addClass(searchTips[this._tooltip.currentSelection], 'search-tip-select');
}
else if ((velocity == -1 ) && (this._tooltip.currentSelection <= 0)) { // Going back up to the search box.
this._tooltip.currentSelection = -1;
}
else if (this._tooltip.style.display != 'none') { // regular up/down
this._tooltip.currentSelection += velocity;
L.DomUtil.addClass(searchTips[this._tooltip.currentSelection], 'search-tip-select');
this._input.value = searchTips[this._tooltip.currentSelection]._text;
// scroll:
var tipOffsetTop = searchTips[this._tooltip.currentSelection].offsetTop;
if (tipOffsetTop + searchTips[this._tooltip.currentSelection].clientHeight >= this._tooltip.scrollTop + this._tooltip.clientHeight) {
this._tooltip.scrollTop = tipOffsetTop - this._tooltip.clientHeight + searchTips[this._tooltip.currentSelection].clientHeight;
}
else if (tipOffsetTop <= this._tooltip.scrollTop) {
this._tooltip.scrollTop = tipOffsetTop;
}
}
},
_handleSubmit: function() { //button and tooltip click and enter submit
this._hideAutoType();
this.hideAlert();
this._hideTooltip();
if(this._input.style.display == 'none') //on first click show _input only
this.expand();
else
{
if(this._input.value === '') //hide _input only
this.collapse();
else
{
var loc = this._getLocation(this._input.value);
if(loc===false)
this.showAlert();
else
{
this.showLocation(loc, this._input.value);
this.fire('search_locationfound', {
latlng: loc,
text: this._input.value,
layer: loc.layer ? loc.layer : null
});
}
//this.collapse();
//FIXME if collapse in _handleSubmit hide _markerLoc!
}
}
},
_getLocation: function(key) { //extract latlng from _recordsCache
if( this._recordsCache.hasOwnProperty(key) )
return this._recordsCache[key];//then after use .loc attribute
else
return false;
},
showLocation: function(latlng, title) { //set location on map from _recordsCache
if(this.options.zoom)
this._map.setView(latlng, this.options.zoom);
else
this._map.panTo(latlng);
if(this._markerLoc)
{
this._markerLoc.setLatLng(latlng); //show circle/marker in location found
this._markerLoc.setTitle(title);
this._markerLoc.show();
if(this.options.animateLocation)
this._markerLoc.animate();
//TODO showLocation: start animation after setView or panTo, maybe with map.on('moveend')...
}
//FIXME autoCollapse option hide this._markerLoc before that visualized!!
if(this.options.autoCollapse)
this.collapse();
return this;
}
});
var SearchMarker = L.Marker.extend({
includes: L.Mixin.Events,
options: {
radius: 10,
weight: 3,
color: '#e03',
stroke: true,
fill: false,
title: '',
//TODO add custom icon!
marker: false //show icon optional, show only circleLoc
},
initialize: function (latlng, options) {
L.setOptions(this, options);
L.Marker.prototype.initialize.call(this, latlng, options);
this._circleLoc = new L.CircleMarker(latlng, this.options);
//TODO add inner circle
},
onAdd: function (map) {
L.Marker.prototype.onAdd.call(this, map);
map.addLayer(this._circleLoc);
this.hide();
},
onRemove: function (map) {
L.Marker.prototype.onRemove.call(this, map);
map.removeLayer(this._circleLoc);
},
setLatLng: function (latlng) {
L.Marker.prototype.setLatLng.call(this, latlng);
this._circleLoc.setLatLng(latlng);
return this;
},
setTitle: function(title) {
title = title || '';
this.options.title = title;
if(this._icon)
this._icon.title = title;
return this;
},
show: function() {
if(this.options.marker)
{
if(this._icon)
this._icon.style.display = 'block';
if(this._shadow)
this._shadow.style.display = 'block';
//this._bringToFront();
}
if(this._circleLoc)
{
this._circleLoc.setStyle({fill: this.options.fill, stroke: this.options.stroke});
//this._circleLoc.bringToFront();
}
return this;
},
hide: function() {
if(this._icon)
this._icon.style.display = 'none';
if(this._shadow)
this._shadow.style.display = 'none';
if(this._circleLoc)
this._circleLoc.setStyle({fill: false, stroke: false});
return this;
},
animate: function() {
//TODO refact animate() more smooth! like this: http://goo.gl/DDlRs
var circle = this._circleLoc,
tInt = 200, //time interval
ss = 10, //frames
mr = parseInt(circle._radius/ss),
oldrad = this.options.radius,
newrad = circle._radius * 2.5,
acc = 0;
circle._timerAnimLoc = setInterval(function() {
acc += 0.5;
mr += acc; //adding acceleration
newrad -= mr;
circle.setRadius(newrad);
if(newrad<oldrad)
{
clearInterval(circle._timerAnimLoc);
circle.setRadius(oldrad);//reset radius
//if(typeof afterAnimCall == 'function')
//afterAnimCall();
//TODO use create event 'animateEnd' in SearchMarker
}
}, tInt);
return this;
}
});
L.Map.addInitHook(function () {
if (this.options.searchControl) {
this.searchControl = L.control.search(this.options.searchControl);
this.addControl(this.searchControl);
}
});
L.control.search = function (options) {
return new L.Control.Search(options);
};
}).call(this);

View file

@ -1,104 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Leaflet.Control.Search</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="style.css" />
</head>
<body id="home">
<h2>Leaflet.Control.Search</h2>
<div id="desc">
A Leaflet Control for search markers/features location by attribute<br />
and much more.
<div style="position:absolute;top:0;right:-120px">
<iframe src="http://ghbtns.com/github-btn.html?user=stefanocudini&amp;repo=leaflet-search&amp;type=watch&amp;count=true" allowtransparency="true" frameborder="0" scrolling="0" width="104px" height="20px"></iframe>
</div>
<br />
Other useful stuff for <a href="http://labs.easyblog.it/maps/">Web Mapping...</a>
</div>
<div style="clear:both"></div>
<div class="contents">
<h4>Features</h4>
<ul id="ff">
<li>Autocomplete</li>
<li>No require external Ajax libs</li>
<li>Retrieve data locations by Ajax/Jsonp</li>
<li>Pre-filtering data from Ajax/Jsonp</li>
<li>Complete fields remapping for remote Jsonp service</li>
<li>Data source callback support</li>
<li>Localization placeholder and text alert</li>
<li>Autozoom on location founded</li>
<li>Autoresize textbox</li>
<li>Customize tooltip menu</li>
<li>Many options to customize the behavior</li>
<li>Support search in features collection</li>
<li>Render Search Box Outside the Leaflet Map</li>
</ul>
</div>
<div class="contents">
<h4>Examples</h4>
<ul id="examples">
<li><a href="examples/simple.html">Simple</a></li>
<li><a href="examples/outside.html">Outside the Map</a></li>
<li><a href="examples/geojson-layer.html">GeoJSON features</a></li>
<li><a href="examples/ajax.html">Ajax</a></li>
<li><a href="examples/jsonp.html">Jsonp</a></li>
<li><a href="examples/ajax-jquery.html">Ajax by jQuery</a></li>
<li><a href="examples/calldata.html">Static data</a></li>
<li><a href="examples/jsonp-filtered.html">Jsonp Filtered</a></li>
<li><a href="examples/ajax-bulk.html">Bulk data</a></li>
<li><a href="examples/custom-tip.html">Custom Tip Item</a></li>
<li><a href="examples/google-geocoding.html">GeoCode Search - Google Geocoding API</a></li>
<li><a href="examples/nominatim.html">GeoCode Search - OSM Nominatim API</a></li>
<li><a href="examples/cloudmade.html">GeoCode Search - Cloudmade API</a></li>
<li><a href="examples/mobile.html">Mobile styled</a></li>
</ul>
</div>
<div class="contents">
<h4>Code repositories</h4>
<a target="_blank" href="https://github.com/stefanocudini/leaflet-search">Github.com</a>
<br />
<a target="_blank" href="https://bitbucket.org/zakis_/leaflet-search">Bitbucket.org</a>
<br />
<a target="_blank" href="https://npmjs.org/package/leaflet-search">Node Packaged Module</a>
<br />
<a target="_blank" href="https://atmosphere.meteor.com/package/leaflet-search">Atmosphere Meteor JS</a>
<br />
<h4>Website</h4>
<a href="http://labs.easyblog.it/maps/leaflet-search/">labs.easyblog.it/maps/leaflet-search</a>
<br />
<h4>Download</h4>
<ul>
<li><a href="https://github.com/stefanocudini/leaflet-search/archive/master.zip">Dev Pack (.zip)</a></li>
<li><a href="dist/leaflet-search.src.js">Source Code (.js)</a></li>
<li><a href="dist/leaflet-search.min.js">Compressed (.min.js)</a></li>
</ul>
</div>
<div id="copy"><a href="http://labs.easyblog.it/">Labs</a> &bull; <a rel="author" href="http://labs.easyblog.it/stefano-cudini/">Stefano Cudini</a></div>
<a href="https://github.com/stefanocudini/leaflet-search"><img id="ribbon" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a>
<div style="clear:both;font-size:.85em;margin-bottom:1em">
<b>For questions and bugs</b> I recommend you to <a href="https://github.com/stefanocudini/leaflet-search/issues">create New Issue</a> on Github repository.</strong><br />
Or to obtain a fast response consult <a href="https://groups.google.com/forum/?hl=it&fromgroups=#!forum/leaflet-js">Official Leaflet community forum</a>.<br />
<br />
This is a micro discussion area for methods of implementation.<br />
</div>
<div id="comments">
<div id="disqus_thread"></div>
</div>
<script>var disqus_shortname = 'easyblog-it'</script>
<script type="text/javascript" src="/labs-common.js"></script>
</body>
</html>

View file

@ -1,11 +0,0 @@
Package.describe({
summary: "Leaflet Control Search"
});
Package.on_use(function (api, where) {
api.add_files('dist/leaflet-search.min.js', 'client');
api.add_files('dist/leaflet-search.min.css', 'client');
api.add_files('images/search-icon.png', 'client');
api.add_files('images/loader.gif', 'client');
//TODO server-side searching...
});

View file

@ -1,35 +0,0 @@
{
"name": "leaflet-search",
"version": "1.5.1",
"description": "Leaflet Control for searching markers/features by attribute on map or remote searching in jsonp/ajax",
"repository": {
"type": "git",
"url": "git@github.com:stefanocudini/leaflet-search.git"
},
"homepage": "http://labs.easyblog.it/maps/leaflet-search/",
"author": {
"name": "Stefano Cudini",
"email": "stefano.cudini@gmail.com",
"url": "http://labs.easyblog.it/"
},
"license": "MIT",
"keywords": [
"gis",
"map",
"leaflet"
],
"dependencies": {
"leaflet": "*"
},
"devDependencies": {
"grunt": "~0.4.2",
"grunt-cli": "~0.1.11",
"grunt-contrib-uglify": "~0.2.7",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-cssmin": "~0.7.0",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-watch": "~0.5.3",
"grunt-todos": "~0.2.0"
}
}

View file

@ -1,8 +0,0 @@
{
"name": "leaflet-search",
"description": "Leaflet Control for searching markers/features by attribute on map or remote searching in jsonp/ajax",
"homepage": "http://labs.easyblog.it/maps/leaflet-search/",
"author": "Stefano Cudini <stefano.cudini@gmail.com>",
"version": "1.5.1",
"git": "https://github.com/stefanocudini/leaflet-search.git"
}

View file

@ -1,121 +0,0 @@
.leaflet-container .leaflet-control-search {
position:relative;
float:left;
background:#fff;
color:#1978cf;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
background-color: rgba(255, 255, 255, 0.8);
z-index:1000;
box-shadow: 0 1px 7px rgba(0,0,0,0.65);
margin-left: 10px;
margin-top: 10px;
}
.leaflet-control-search.search-exp {/*expanded*/
box-shadow: 0 1px 7px #999;
background: #fff;
}
.leaflet-control-search .search-input {
display:block;
float:left;
background: #fff;
border:1px solid #666;
border-radius:2px;
height:18px;
padding:0 18px 0 2px;
margin:3px 0 3px 3px;
}
.leaflet-control-search.search-load .search-input {
background: url('../images/loader.gif') no-repeat center right #fff;
}
.leaflet-control-search.search-load .search-cancel {
visibility:hidden;
}
.leaflet-control-search .search-cancel {
display:block;
width:22px;
height:18px;
position:absolute;
right:22px;
margin:3px 0;
background: url('../images/search-icon.png') no-repeat 0 -46px;
text-decoration:none;
filter: alpha(opacity=80);
opacity: 0.8;
}
.leaflet-control-search .search-cancel:hover {
filter: alpha(opacity=100);
opacity: 1;
}
.leaflet-control-search .search-cancel span {
display:none;/* comment for cancel button imageless */
font-size:18px;
line-height:20px;
color:#ccc;
font-weight:bold;
}
.leaflet-control-search .search-cancel:hover span {
color:#aaa;
}
.leaflet-control-search .search-button {
display:block;
float:left;
width:26px;
height:26px;
background: url('../images/search-icon.png') no-repeat 2px 2px;
border-radius:4px;
}
.leaflet-control-search .search-button:hover {
background: url('../images/search-icon.png') no-repeat 2px -22px;
}
.leaflet-control-search .search-tooltip {
position:absolute;
top:100%;
left:0;
float:left;
min-width:80px;
max-height:106px;/*(.search-tip height * 5)*/
box-shadow: 0 0 8px rgba(0,0,0,0.4);
-webkit-border-radius: 5px;
-webkit-border-top-left-radius: 0;
-moz-border-radius: 5px;
-moz-border-radius-topleft: 0;
border-radius: 5px;
border-top-left-radius: 0;
background-color: rgba(0, 0, 0, 0.25);
z-index:1010;
overflow-y:auto;
overflow-x:hidden;
}
.leaflet-control-search .search-tip {
font-size:.85em;
margin:2px;
padding:2px;
display:block;
color:black;
background: #ddd;
border-radius:.25em;
text-decoration:none;
white-space:nowrap;
font-size:.85em;
vertical-align:center;
}
.leaflet-control-search .search-tip-select,
.leaflet-control-search .search-tip:hover,
.leaflet-control-search .search-button:hover {
background-color: #fff;
}
.leaflet-control-search .search-alert {
cursor:pointer;
clear:both;
font-size:.75em;
margin-bottom:5px;
padding:0 .25em;
color:#e00;
font-weight:bold;
border-radius:.25em;
}

Some files were not shown because too many files have changed in this diff Show more