From cec17a1c2659f81b172882cd28cc3dc81f3f0d9d Mon Sep 17 00:00:00 2001 From: Norbert Renner Date: Wed, 14 May 2014 15:07:50 +0200 Subject: [PATCH] update Leaflet.Elevation --- .../dist/Leaflet.Elevation-0.0.1.css | 1 - .../dist/Leaflet.Elevation-0.0.1.min.js | 2 - .../dist/Leaflet.Elevation-0.0.1.src.js | 449 ------- .../dist/Leaflet.Elevation-0.0.2.css | 1 + .../dist/Leaflet.Elevation-0.0.2.min.js | 2 + .../dist/Leaflet.Elevation-0.0.2.src.js | 675 ++++++++++ .../dist/images/elevation.png | Bin 687 -> 683 bytes .../src/L.Control.Elevation.js | 1142 ++++++++++------- .../src/css/L.Control.Elevation.less | 3 + .../src/css/themes/lime.less | 2 + .../src/css/themes/purple.less | 2 + .../src/css/themes/steelblue.less | 4 +- index.html | 2 +- js/plugin/Elevation.js | 4 +- 14 files changed, 1360 insertions(+), 929 deletions(-) delete mode 100644 bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.css delete mode 100644 bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.min.js delete mode 100644 bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.src.js create mode 100644 bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.css create mode 100644 bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.min.js create mode 100644 bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.src.js diff --git a/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.css b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.css deleted file mode 100644 index 07123a8..0000000 --- a/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.css +++ /dev/null @@ -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 path,.lime-theme .leaflet-control.elevation .axis line{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-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 path,.steelblue-theme .leaflet-control.elevation .axis line{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-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 path,.purple-theme .leaflet-control.elevation .axis line{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-overlay-pane .height-focus{stroke:#732c7b;fill:#732c7b}.purple-theme .leaflet-overlay-pane .height-focus.line{pointer-events:none;stroke-width:2} \ No newline at end of file diff --git a/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.min.js b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.min.js deleted file mode 100644 index fbaa0ad..0000000 --- a/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.1.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! Leaflet.Elevation 25-10-2013 */ -L.Control.Elevation=L.Control.extend({options:{position:"topright",theme:"lime-theme",width:600,height:175,margins:{top:10,right:20,bottom:30,left:50},useHeightIndicator:!0,interpolation:"linear",hoverNumber:{decimalsX:3,decimalsY:0,formatter:void 0},xTicks:void 0,yTicks:void 0,collapsed:!1},onRemove:function(){this._container=null,this._data=null,this._dist=null},onAdd:function(a){this._map=a;var b=this.options,c=b.margins;b.width=b.width-c.left-c.right,b.height=b.height-c.top-c.bottom,b.xTicks=b.xTicks||Math.round(b.width/75),b.yTicks=b.yTicks||Math.round(b.height/30),b.hoverNumber.formatter=b.hoverNumber.formatter||this._formatter,d3.select("body").classed(b.theme,!0);var d=this._x=d3.scale.linear().range([0,b.width]),e=this._y=d3.scale.linear().range([b.height,0]);this._area=d3.svg.area().interpolate(b.interpolation).x(function(a){return d(a.dist)}).y0(b.height).y1(function(a){return e(a.altitude)});var f=this._container=L.DomUtil.create("div","elevation");this._initToggle();var g=b.width+c.left+c.right,h=d3.select(f);h.attr("width",g);var i=h.append("svg");i.attr("width",g).attr("class","background").attr("height",b.height+c.top+c.bottom).append("g").attr("transform","translate("+c.left+","+c.top+")");var j=d3.svg.line();j=j.x(function(){return d3.mouse(i.select("g"))[0]}).y(function(){return b.height});var k=d3.select(this._container).select("svg").select("g");this._areapath=k.append("path").attr("class","area");var l=this._background=k.append("rect").attr("width",b.width).attr("height",b.height).style("fill","none").style("stroke","none").style("pointer-events","all");l.on("mousemove",this._mousemoveHandler.bind(this)),l.on("mouseout",this._mouseoutHandler.bind(this)),this._xaxisgraphicnode=k.append("g"),this._yaxisgraphicnode=k.append("g"),this._appendXaxis(this._xaxisgraphicnode),this._appendYaxis(this._yaxisgraphicnode);var m=this._focusG=k.append("g");return this._mousefocus=m.append("svg:line").attr("class","mouse-focus-line").attr("x2","0").attr("y2","0").attr("x1","0").attr("y1","0"),this._focuslabelX=m.append("svg:text").style("pointer-events","none").attr("class","mouse-focus-label-x"),this._focuslabelY=m.append("svg:text").style("pointer-events","none").attr("class","mouse-focus-label-y"),f},_initToggle:function(){var a=this._container;if(a.setAttribute("aria-haspopup",!0),L.Browser.touch?L.DomEvent.on(a,"click",L.DomEvent.stopPropagation):L.DomEvent.disableClickPropagation(a),this.options.collapsed){this._collapse(),L.Browser.android||L.DomEvent.on(a,"mouseover",this._expand,this).on(a,"mouseout",this._collapse,this);var b=this._button=L.DomUtil.create("a","elevation-toggle",a);b.href="#",b.title="Elevation",L.Browser.touch?L.DomEvent.on(b,"click",L.DomEvent.stop).on(b,"click",this._expand,this):L.DomEvent.on(b,"focus",this._expand,this),this._map.on("click",this._collapse,this)}},_expand:function(){this._container.className=this._container.className.replace(" elevation-collapsed","")},_collapse:function(){L.DomUtil.addClass(this._container,"elevation-collapsed")},_formatter:function(a,b,c){var d;d=0===b?Math.round(a)+"":L.Util.formatNum(a,b)+"";var e=d.split(".");if(e[1]){for(var f=b-e[1].length;f>0;f--)e[1]+="0";d=e.join(c||".")}return d},_appendYaxis:function(a){a.attr("class","y axis").call(d3.svg.axis().scale(this._y).ticks(this.options.yTicks).orient("left")).append("text").attr("x",15).style("text-anchor","end").text("m")},_appendXaxis:function(a){a.attr("class","x axis").attr("transform","translate(0,"+this.options.height+")").call(d3.svg.axis().scale(this._x).ticks(this.options.xTicks).orient("bottom")).append("text").attr("x",this.options.width+15).style("text-anchor","end").text("km")},_updateAxis:function(){this._xaxisgraphicnode.selectAll("axis").remove(),this._yaxisgraphicnode.selectAll("axis").remove(),this._appendXaxis(this._xaxisgraphicnode),this._appendYaxis(this._yaxisgraphicnode)},_mouseoutHandler:function(){this._marker&&(this._map.removeLayer(this._marker),this._marker=null),this._mouseHeightFocus&&(this._mouseHeightFocus.style("visibility","hidden"),this._mouseHeightFocusLabel.style("visibility","hidden")),this._pointG&&this._pointG.style("visibility","hidden"),this._focusG.style("visibility","hidden")},_mousemoveHandler:function(){if(this._data&&0!==this._data.length){var a=d3.mouse(this._background.node()),b=this.options;this._focusG.style("visibility","visible"),this._mousefocus.attr("x1",a[0]).attr("y1",0).attr("x2",a[0]).attr("y2",b.height).classed("hidden",!1);var c=d3.bisector(function(a){return a.dist}).left,d=this._x.invert(a[0]),e=c(this._data,d),f=this._data[e].altitude,g=this._data[e].dist,h=this._data[e].latlng,i=b.hoverNumber.formatter(f,b.hoverNumber.decimalsY),j=b.hoverNumber.formatter(g,b.hoverNumber.decimalsX);this._focuslabelX.attr("x",a[0]).text(i+" m"),this._focuslabelY.attr("y",b.height-5).attr("x",a[0]).text(j+" km");var k=this._map.latLngToLayerPoint(h);if(b.useHeightIndicator){if(!this._mouseHeightFocus){var l=d3.select(".leaflet-overlay-pane svg").append("g");this._mouseHeightFocus=l.append("svg:line").attr("class","height-focus line").attr("x2","0").attr("y2","0").attr("x1","0").attr("y1","0");var m=this._pointG=l.append("g");m.append("svg:circle").attr("r",6).attr("cx",0).attr("cy",0).attr("class","height-focus circle-lower"),this._mouseHeightFocusLabel=l.append("svg:text").attr("class","height-focus-label").style("pointer-events","none")}var n=this.options.height/this._maxElevation*f,o=k.y-n;this._mouseHeightFocus.attr("x1",k.x).attr("x2",k.x).attr("y1",k.y).attr("y2",o).style("visibility","visible"),this._pointG.attr("transform","translate("+k.x+","+k.y+")").style("visibility","visible"),this._mouseHeightFocusLabel.attr("x",k.x).attr("y",o).text(f+" m").style("visibility","visible")}else this._marker?this._marker.setLatLng(h):this._marker=new L.Marker(h).addTo(this._map)}},_addGeoJSONData:function(a){if(a){for(var b=this._data||[],c=this._dist||0,d=this._maxElevation||0,e=0;e 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", 15) - .style("text-anchor", "end") - .text("m"); - }, - - _appendXaxis: function(x) { - x.attr("class", "x axis") - .attr("transform", "translate(0," + this.options.height + ")") - .call(d3.svg.axis() - .scale(this._x) - .ticks(this.options.xTicks) - .orient("bottom")) - .append("text") - .attr("x", this.options.width + 15) - .style("text-anchor", "end") - .text("km"); - }, - - _updateAxis: function() { - this._xaxisgraphicnode.selectAll("axis").remove(); - this._yaxisgraphicnode.selectAll("axis").remove(); - this._appendXaxis(this._xaxisgraphicnode); - this._appendYaxis(this._yaxisgraphicnode); - }, - - _mouseoutHandler: 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"); - }, - - _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', opts.height) - .classed('hidden', false); - var bisect = d3.bisector(function(d) { - return d.dist; - }).left; - - var xinvert = this._x.invert(coords[0]), - item = bisect(this._data, xinvert), - alt = this._data[item].altitude, - dist = this._data[item].dist, - ll = this._data[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", opts.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.options.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 + newdist / 1000; - 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 + newdist / 1000; - 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); - } - }, - - /* - * Add data to the diagram either from GPX or GeoJSON and - * update the axis domain and data - */ - addData: function(d) { - - this._addData(d); - - var xdomain = d3.extent(this._data, function(d) { - return d.dist; - }); - var ydomain = d3.extent(this._data, function(d) { - return d.altitude; - }); - - this._x.domain(xdomain); - this._y.domain(ydomain); - this._areapath.datum(this._data) - .attr("d", this._area); - this._updateAxis(); - return; - } - -}); - -L.control.elevation = function(options) { - return new L.Control.Elevation(options); -}; \ No newline at end of file diff --git a/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.css b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.css new file mode 100644 index 0000000..d907ef6 --- /dev/null +++ b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.css @@ -0,0 +1 @@ +.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} \ No newline at end of file diff --git a/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.min.js b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.min.js new file mode 100644 index 0000000..404505e --- /dev/null +++ b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.min.js @@ -0,0 +1,2 @@ +/*! Leaflet.Elevation 05-03-2014 */ +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:!0,interpolation:"linear",hoverNumber:{decimalsX:3,decimalsY:0,formatter:void 0},xTicks:void 0,yTicks:void 0,collapsed:!1,yAxisMin:void 0,yAxisMax:void 0,forceAxisBounds:!1},onRemove:function(){this._container=null},onAdd:function(a){this._map=a;var b=this.options,c=b.margins;b.xTicks=b.xTicks||Math.round(this._width()/75),b.yTicks=b.yTicks||Math.round(this._height()/30),b.hoverNumber.formatter=b.hoverNumber.formatter||this._formatter,d3.select("body").classed(b.theme,!0);var d=this._x=d3.scale.linear().range([0,this._width()]),e=this._y=d3.scale.linear().range([this._height(),0]),f=(this._area=d3.svg.area().interpolate(b.interpolation).x(function(a){return d(a.dist)}).y0(this._height()).y1(function(a){return e(a.altitude)}),this._container=L.DomUtil.create("div","elevation"));this._initToggle();var g=d3.select(f);g.attr("width",b.width);var h=g.append("svg");h.attr("width",b.width).attr("class","background").attr("height",b.height).append("g").attr("transform","translate("+c.left+","+c.top+")");var i=d3.svg.line();i=i.x(function(){return d3.mouse(h.select("g"))[0]}).y(function(){return this._height()});var j=d3.select(this._container).select("svg").select("g");this._areapath=j.append("path").attr("class","area");var k=this._background=j.append("rect").attr("width",this._width()).attr("height",this._height()).style("fill","none").style("stroke","none").style("pointer-events","all");L.Browser.touch?(k.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)):(k.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=j.append("g"),this._yaxisgraphicnode=j.append("g"),this._appendXaxis(this._xaxisgraphicnode),this._appendYaxis(this._yaxisgraphicnode);var l=this._focusG=j.append("g");return this._mousefocus=l.append("svg:line").attr("class","mouse-focus-line").attr("x2","0").attr("y2","0").attr("x1","0").attr("y1","0"),this._focuslabelX=l.append("svg:text").style("pointer-events","none").attr("class","mouse-focus-label-x"),this._focuslabelY=l.append("svg:text").style("pointer-events","none").attr("class","mouse-focus-label-y"),this._data&&this._applyData(),f},_dragHandler:function(){d3.event.preventDefault(),d3.event.stopPropagation(),this._gotDragged=!0,this._drawDragRectangle()},_drawDragRectangle:function(){if(this._dragStartCoords){var a=this._dragCurrentCoords=d3.mouse(this._background.node()),b=Math.min(this._dragStartCoords[0],a[0]),c=Math.max(this._dragStartCoords[0],a[0]);if(this._dragRectangle||this._dragRectangleG)this._dragRectangle.attr("width",c-b).attr("x",b);else{var d=d3.select(this._container).select("svg").select("g");this._dragRectangleG=d.append("g"),this._dragRectangle=this._dragRectangleG.append("rect").attr("width",c-b).attr("height",this._height()).attr("x",b).attr("class","mouse-drag").style("pointer-events","none")}}},_resetDrag:function(){this._dragRectangleG&&(this._dragRectangleG.remove(),this._dragRectangleG=null,this._dragRectangle=null,this._hidePositionMarker(),this._map.fitBounds(this._fullExtent))},_dragEndHandler:function(){if(!this._dragStartCoords||!this._gotDragged)return this._dragStartCoords=null,this._gotDragged=!1,void this._resetDrag();this._hidePositionMarker();var a=this._findItemForX(this._dragStartCoords[0]),b=this._findItemForX(this._dragCurrentCoords[0]);this._fitSection(a,b),this._dragStartCoords=null,this._gotDragged=!1},_dragStartHandler:function(){d3.event.preventDefault(),d3.event.stopPropagation(),this._gotDragged=!1,this._dragStartCoords=d3.mouse(this._background.node())},_findItemForX:function(a){var b=d3.bisector(function(a){return a.dist}).left,c=this._x.invert(a);return b(this._data,c)},_fitSection:function(a,b){var c=Math.min(a,b),d=Math.max(a,b),e=this._calculateFullExtent(this._data.slice(c,d));this._map.fitBounds(e)},_initToggle:function(){var a=this._container;if(a.setAttribute("aria-haspopup",!0),L.Browser.touch?L.DomEvent.on(a,"click",L.DomEvent.stopPropagation):L.DomEvent.disableClickPropagation(a),this.options.collapsed){this._collapse(),L.Browser.android||L.DomEvent.on(a,"mouseover",this._expand,this).on(a,"mouseout",this._collapse,this);var b=this._button=L.DomUtil.create("a","elevation-toggle",a);b.href="#",b.title="Elevation",L.Browser.touch?L.DomEvent.on(b,"click",L.DomEvent.stop).on(b,"click",this._expand,this):L.DomEvent.on(b,"focus",this._expand,this),this._map.on("click",this._collapse,this)}},_expand:function(){this._container.className=this._container.className.replace(" elevation-collapsed","")},_collapse:function(){L.DomUtil.addClass(this._container,"elevation-collapsed")},_width:function(){var a=this.options;return a.width-a.margins.left-a.margins.right},_height:function(){var a=this.options;return a.height-a.margins.top-a.margins.bottom},_formatter:function(a,b,c){var d;d=0===b?Math.round(a)+"":L.Util.formatNum(a,b)+"";var e=d.split(".");if(e[1]){for(var f=b-e[1].length;f>0;f--)e[1]+="0";d=e.join(c||".")}return d},_appendYaxis:function(a){a.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(a){a.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()},_hidePositionMarker:function(){this._marker&&(this._map.removeLayer(this._marker),this._marker=null),this._mouseHeightFocus&&(this._mouseHeightFocus.style("visibility","hidden"),this._mouseHeightFocusLabel.style("visibility","hidden")),this._pointG&&this._pointG.style("visibility","hidden"),this._focusG.style("visibility","hidden")},_mousemoveHandler:function(){if(this._data&&0!==this._data.length){var a=d3.mouse(this._background.node()),b=this.options;this._focusG.style("visibility","visible"),this._mousefocus.attr("x1",a[0]).attr("y1",0).attr("x2",a[0]).attr("y2",this._height()).classed("hidden",!1);var c=(d3.bisector(function(a){return a.dist}).left,this._data[this._findItemForX(a[0])]),d=c.altitude,e=c.dist,f=c.latlng,g=b.hoverNumber.formatter(d,b.hoverNumber.decimalsY),h=b.hoverNumber.formatter(e,b.hoverNumber.decimalsX);this._focuslabelX.attr("x",a[0]).text(g+" m"),this._focuslabelY.attr("y",this._height()-5).attr("x",a[0]).text(h+" km");var i=this._map.latLngToLayerPoint(f);if(b.useHeightIndicator){if(!this._mouseHeightFocus){var j=d3.select(".leaflet-overlay-pane svg").append("g");this._mouseHeightFocus=j.append("svg:line").attr("class","height-focus line").attr("x2","0").attr("y2","0").attr("x1","0").attr("y1","0");var k=this._pointG=j.append("g");k.append("svg:circle").attr("r",6).attr("cx",0).attr("cy",0).attr("class","height-focus circle-lower"),this._mouseHeightFocusLabel=j.append("svg:text").attr("class","height-focus-label").style("pointer-events","none")}var l=this._height()/this._maxElevation*d,m=i.y-l;this._mouseHeightFocus.attr("x1",i.x).attr("x2",i.x).attr("y1",i.y).attr("y2",m).style("visibility","visible"),this._pointG.attr("transform","translate("+i.x+","+i.y+")").style("visibility","visible"),this._mouseHeightFocusLabel.attr("x",i.x).attr("y",m).text(d+" m").style("visibility","visible")}else this._marker?this._marker.setLatLng(f):this._marker=new L.Marker(f).addTo(this._map)}},_addGeoJSONData:function(a){if(a){for(var b=this._data||[],c=this._dist||0,d=this._maxElevation||0,e=0;eb[1]||c.forceAxisBounds)&&(b[1]=c.yAxisMax),this._x.domain(a),this._y.domain(b),this._areapath.datum(this._data).attr("d",this._area),this._updateAxis(),this._fullExtent=this._calculateFullExtent(this._data)},_clearData:function(){this._data=null,this._dist=null,this._maxElevation=null},clear:function(){this._clearData(),this._areapath&&(this._areapath.attr("d","M0 0"),this._x.domain([0,1]),this._y.domain([0,1]),this._updateAxis())}}),L.control.elevation=function(a){return new L.Control.Elevation(a)}; \ No newline at end of file diff --git a/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.src.js b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.src.js new file mode 100644 index 0000000..cb2e31e --- /dev/null +++ b/bower_components/Leaflet.Elevation/dist/Leaflet.Elevation-0.0.2.src.js @@ -0,0 +1,675 @@ +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); +}; \ No newline at end of file diff --git a/bower_components/Leaflet.Elevation/dist/images/elevation.png b/bower_components/Leaflet.Elevation/dist/images/elevation.png index 68fb537e42d5d95807e000643cc44ba9c326f6b2..b2c291e5b333ed63ae974872c8705397c4e27ee7 100644 GIT binary patch delta 635 zcmV->0)+jq1*-*+JAV$u000ie0hKEb8vpKl}l(7Q51&1Gnq-!7d0(O z+M4uXNLx#bS_@Utg|383L9l|Zb*C|9KwVS^+$y5D(!C4&5L9p_3SGD?;zHZ%pwVhI zYK_LyByBRTBB2jjZAK9MSNER7IUoPwKH$Ip8R@!SrtA6{yMOvC`NjPFd^yl>JIHRW z2^1ZnwttYLwt@@;g&Yqo;imBj)izL~ofAMCK;kn8Z2?6_Xcy#CMM>2shoXHE3mpsj z6VQsIIC&qJI_J18ijr#!?R@esZu+L;i__5|t^)%iY;$TZx28J%0zC*9`v!5W+0og1 z6}_oc^0;?HAXZb=7zc2u&aBrHG~+X|UIhGAP2(-~U1q-K{fwD@`DSc;9UKB~t?DQ; z#DP>QdB>%d%!cc`o)_jC{cUl8ps)2=Aq1e-v+1K#bAQhW3>e1JzDok?0+Th>p%<+U z-D9evWeam|S9y9%c;9GKUB|1%bs}Qb`&wfN?THS0R|Q=@!en!>bF#AB`+ac^pt7tw zxm+Be)*G7ERM$6hoLhW4i~0l!iWTrS$3*BnHOzk7KmY+>^OWjv{t!4{=&I--5yjf* z4Zj9{Vs zO*5e;lgabIF+i~_t1^?xOcWaw3aiVex@@BgqKkLRnRD1CN;egf9W Vu7>vUre6R6002ovPDHLkV1na@Cyf9A delta 639 zcmV-_0)YLi1+N8=JAVrk000XU0RWnu7ytkQQAtEWR7i>Kl}$)gQ5462_s)AWV=6W_ zANeurFs3GBP)11<(JnBApom)6uBMR()xvzxwuqut?OXU2RM094T(p#EQ8qD|W|>+x zHHkB$zT0YI@B=O91wsGSz2|VwkN@F*z<>QSG7O{GFpP_K^?#SS#r*ty3D9Xf$Zo9* z6dRzTvxif*f=m;M#bYJ8Yd%G@4U~*<7H9@Ye&(nxpy&V*fw)%cE}xb{{~|056yi@n ztB&H_BV3L-$2}>e)m-29{Qcxx|HtX!y|DrI-B3J>^>am8v2$i>y6y}}XjhV}$9r+C+tHWr_fYIN(C&=i0}*BAYs>crH{SO)?Ep1R@2+SWv_=EKZLCNVbDTB$e&^sMP9 z+Q*S}I(6Tr70rfgcfZQd)%lyJ0D`{8m-!HYN>6Cgseij>grLhbm-k&3&=!aX%In@V z)$SQ`N^LPe=XMuocGMpn3{^!&mevV@s_{3CB8Vhg=vWhU{Uq_mn$~z(srUQR9Khxh zZ)&ADK!rCnp=qvf%Hs0U(^=3bNC<}t`Wi;1VAuJ64%-F-sP>1)HHY&Ditc<@1qTV? zP?g^LcX&e37VG6uF22fzmE#+M1p`eJO(STtXp9&4h>F@ur9*^g%l=8S; Zpr3*_wRy^$)w=)y002ovPDHLkV1iKXH`4$B diff --git a/bower_components/Leaflet.Elevation/src/L.Control.Elevation.js b/bower_components/Leaflet.Elevation/src/L.Control.Elevation.js index c58edd0..cb2e31e 100644 --- a/bower_components/Leaflet.Elevation/src/L.Control.Elevation.js +++ b/bower_components/Leaflet.Elevation/src/L.Control.Elevation.js @@ -1,479 +1,675 @@ L.Control.Elevation = L.Control.extend({ - options: { - position: "topright", - theme: "lime-theme", - width: 600, - height: 175, - margins: { - top: 10, - right: 20, - bottom: 30, - left: 50 - }, - useHeightIndicator: true, - interpolation: "linear", - hoverNumber: { - decimalsX: 3, - decimalsY: 0, - formatter: undefined - }, - xTicks: undefined, - yTicks: undefined, - collapsed: false - }, - - onRemove: function(map) { - this._container = null; - this._data = null; - this._dist = null; - }, - - onAdd: function(map) { - this._map = map; - - var opts = this.options; - var margin = opts.margins; - opts.width = opts.width - margin.left - margin.right; - opts.height = opts.height - margin.top - margin.bottom; - opts.xTicks = opts.xTicks || Math.round(opts.width / 75); - opts.yTicks = opts.yTicks || Math.round(opts.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, opts.width]); - - var y = this._y = d3.scale.linear() - .range([opts.height, 0]); - - var area = this._area = d3.svg.area() - .interpolate(opts.interpolation) - .x(function(d) { - return x(d.dist); - }) - .y0(opts.height) - .y1(function(d) { - return y(d.altitude); - }); - - var container = this._container = L.DomUtil.create("div", "elevation"); - - this._initToggle(); - - var complWidth = opts.width + margin.left + margin.right; - var cont = d3.select(container); - cont.attr("width", complWidth); - var svg = cont.append("svg"); - svg.attr("width", complWidth) - .attr("class", "background") - .attr("height", opts.height + margin.top + margin.bottom) - .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 opts.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", opts.width) - .attr("height", opts.height) - .style("fill", "none") - .style("stroke", "none") - .style("pointer-events", "all"); - - background.on("mousemove", this._mousemoveHandler.bind(this)); - background.on("mouseout", this._mouseoutHandler.bind(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"); - - return container; - }, - - _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'); - }, - - /* - * 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", 15) - .style("text-anchor", "end") - .text("m"); - }, - - _appendXaxis: function(x) { - x.attr("class", "x axis") - .attr("transform", "translate(0," + this.options.height + ")") - .call(d3.svg.axis() - .scale(this._x) - .ticks(this.options.xTicks) - .orient("bottom")) - .append("text") - .attr("x", this.options.width + 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() { - 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"); - }, - - _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', opts.height) - .classed('hidden', false); - var bisect = d3.bisector(function(d) { - return d.dist; - }).left; - - var xinvert = this._x.invert(coords[0]), - item = bisect(this._data, xinvert), - alt = this._data[item].altitude, - dist = this._data[item].dist, - ll = this._data[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", opts.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.options.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 + newdist / 1000; - 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 + newdist / 1000; - 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); - } - }, - - /* - * Add data to the diagram either from GPX or GeoJSON and - * update the axis domain and data - */ - addData: function(d) { - - this._addData(d); - - var xdomain = d3.extent(this._data, function(d) { - return d.dist; - }); - var ydomain = d3.extent(this._data, function(d) { - return d.altitude; - }); - - this._x.domain(xdomain); - this._y.domain(ydomain); - this._areapath.datum(this._data) - .attr("d", this._area); - this._updateAxis(); - return; - }, - - /* - * Reset data - */ - _clearData: function() { - this._data = null; - this._dist = null; - this._maxElevation = null; - }, - - /* - * Reset data and display - */ - clear: function() { - - this._clearData(); - - // 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(); - } + 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); + return new L.Control.Elevation(options); }; \ No newline at end of file diff --git a/bower_components/Leaflet.Elevation/src/css/L.Control.Elevation.less b/bower_components/Leaflet.Elevation/src/css/L.Control.Elevation.less index f111f51..7dce5c3 100644 --- a/bower_components/Leaflet.Elevation/src/css/L.Control.Elevation.less +++ b/bower_components/Leaflet.Elevation/src/css/L.Control.Elevation.less @@ -46,6 +46,9 @@ .mouse-focus-label-x { } + .mouse-drag{ + fill:@drag-color; + } } .leaflet-overlay-pane { diff --git a/bower_components/Leaflet.Elevation/src/css/themes/lime.less b/bower_components/Leaflet.Elevation/src/css/themes/lime.less index 6b7efd8..889c116 100644 --- a/bower_components/Leaflet.Elevation/src/css/themes/lime.less +++ b/bower_components/Leaflet.Elevation/src/css/themes/lime.less @@ -1,6 +1,8 @@ @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; diff --git a/bower_components/Leaflet.Elevation/src/css/themes/purple.less b/bower_components/Leaflet.Elevation/src/css/themes/purple.less index c96082b..b135359 100644 --- a/bower_components/Leaflet.Elevation/src/css/themes/purple.less +++ b/bower_components/Leaflet.Elevation/src/css/themes/purple.less @@ -1,6 +1,8 @@ @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; diff --git a/bower_components/Leaflet.Elevation/src/css/themes/steelblue.less b/bower_components/Leaflet.Elevation/src/css/themes/steelblue.less index f38ec38..ca8f787 100644 --- a/bower_components/Leaflet.Elevation/src/css/themes/steelblue.less +++ b/bower_components/Leaflet.Elevation/src/css/themes/steelblue.less @@ -1,6 +1,8 @@ @theme : steelblue-theme; -@base-color : steelblue; +@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; diff --git a/index.html b/index.html index 8573b68..949624c 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ - + diff --git a/js/plugin/Elevation.js b/js/plugin/Elevation.js index 2e52a9e..535369d 100644 --- a/js/plugin/Elevation.js +++ b/js/plugin/Elevation.js @@ -4,9 +4,9 @@ BR.Elevation = L.Control.Elevation.extend({ width: 385, margins: { top: 20, - right: 20, + right: 30, bottom: 30, - left: 50 + left: 60 }, theme: "steelblue-theme" //purple },