From: Tom Hughes Date: Fri, 7 Nov 2014 08:40:18 +0000 (+0000) Subject: Merge branch 'overpass' X-Git-Tag: live~4846 X-Git-Url: https://git.openstreetmap.org./rails.git/commitdiff_plain/e11d734f9f965464510dd109970501861001ee5c?hp=295c4f69922853d234c72465e9599de46163575c Merge branch 'overpass' --- diff --git a/app/assets/images/sprite.png b/app/assets/images/sprite.png index e7490c84c..e3ed0e7f8 100644 Binary files a/app/assets/images/sprite.png and b/app/assets/images/sprite.png differ diff --git a/app/assets/images/sprite.svg b/app/assets/images/sprite.svg index b61018d13..b50b969e9 100644 --- a/app/assets/images/sprite.svg +++ b/app/assets/images/sprite.svg @@ -13,8 +13,8 @@ height="200" id="svg2" version="1.1" - inkscape:version="0.48.2 r9819" - inkscape:export-filename="/Users/tmcw/src/openstreetmap-website/app/assets/images/sprite.png" + inkscape:version="0.48.4 r9939" + inkscape:export-filename="/home/tom/rails/app/assets/images/sprite.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:docname="sprite.svg"> @@ -27,16 +27,16 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="4" - inkscape:cx="210.42032" - inkscape:cy="175.54808" + inkscape:zoom="16" + inkscape:cx="258.2457" + inkscape:cy="193.60262" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" - inkscape:window-width="1436" - inkscape:window-height="856" - inkscape:window-x="4" - inkscape:window-y="0" + inkscape:window-width="1366" + inkscape:window-height="702" + inkscape:window-x="0" + inkscape:window-y="27" inkscape:window-maximized="1" showguides="true" inkscape:guide-bbox="true" @@ -113,6 +113,10 @@ orientation="1,0" position="260,195" id="guide11761" /> + @@ -265,5 +269,16 @@ inkscape:export-filename="/Users/saman/work_repos/osm-redesign/renders/share-1.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" /> + ? diff --git a/app/assets/javascripts/index.js b/app/assets/javascripts/index.js index 0cf08f845..191f390bf 100644 --- a/app/assets/javascripts/index.js +++ b/app/assets/javascripts/index.js @@ -5,6 +5,7 @@ //= require leaflet.key //= require leaflet.note //= require leaflet.share +//= require leaflet.query //= require index/search //= require index/browse //= require index/export @@ -13,6 +14,7 @@ //= require index/note //= require index/new_note //= require index/changeset +//= require index/query //= require router (function() { @@ -124,6 +126,11 @@ $(document).ready(function () { sidebar: sidebar }).addTo(map); + L.OSM.query({ + position: position, + sidebar: sidebar + }).addTo(map); + L.control.scale() .addTo(map); @@ -305,7 +312,8 @@ $(document).ready(function () { "/node/:id(/history)": OSM.Browse(map, 'node'), "/way/:id(/history)": OSM.Browse(map, 'way'), "/relation/:id(/history)": OSM.Browse(map, 'relation'), - "/changeset/:id": OSM.Changeset(map) + "/changeset/:id": OSM.Changeset(map), + "/query": OSM.Query(map) }); if (OSM.preferred_editor == "remote" && document.location.pathname == "/edit") { diff --git a/app/assets/javascripts/index/query.js b/app/assets/javascripts/index/query.js new file mode 100644 index 000000000..d0e9cc299 --- /dev/null +++ b/app/assets/javascripts/index/query.js @@ -0,0 +1,329 @@ +//= require jquery.simulate + +OSM.Query = function(map) { + var protocol = document.location.protocol === "https:" ? "https:" : "http:", + url = protocol + OSM.OVERPASS_URL, + queryButton = $(".control-query .control-button"), + uninterestingTags = ['source', 'source_ref', 'source:ref', 'history', 'attribution', 'created_by', 'tiger:county', 'tiger:tlid', 'tiger:upload_uuid', 'KSJ2:curve_id', 'KSJ2:lat', 'KSJ2:lon', 'KSJ2:coordinate', 'KSJ2:filename', 'note:ja'], + marker; + + var featureStyle = { + color: "#FF6200", + weight: 4, + opacity: 1, + fillOpacity: 0.5, + clickable: false + }; + + queryButton.on("click", function (e) { + e.preventDefault(); + e.stopPropagation(); + + if (queryButton.hasClass("disabled")) return; + + if (queryButton.hasClass("active")) { + disableQueryMode(); + } else { + enableQueryMode(); + } + }).on("disabled", function (e) { + if (queryButton.hasClass("active")) { + map.off("click", clickHandler); + $(map.getContainer()).removeClass("query-active").addClass("query-disabled"); + $(this).tooltip("show"); + } + }).on("enabled", function (e) { + if (queryButton.hasClass("active")) { + map.on("click", clickHandler); + $(map.getContainer()).removeClass("query-disabled").addClass("query-active"); + $(this).tooltip("hide"); + } + }); + + $("#sidebar_content") + .on("mouseover", ".query-results li.query-result", function () { + var geometry = $(this).data("geometry") + if (geometry) map.addLayer(geometry); + $(this).addClass("selected"); + }) + .on("mouseout", ".query-results li.query-result", function () { + var geometry = $(this).data("geometry") + if (geometry) map.removeLayer(geometry); + $(this).removeClass("selected"); + }) + .on("mousedown", ".query-results li.query-result", function (e) { + var moved = false; + $(this).one("click", function (e) { + if (!moved) { + var geometry = $(this).data("geometry") + if (geometry) map.removeLayer(geometry); + + if (!$(e.target).is('a')) { + $(this).find("a").simulate("click", e); + } + } + }).one("mousemove", function () { + moved = true; + }); + }); + + function interestingFeature(feature, origin, radius) { + if (feature.tags) { + for (var key in feature.tags) { + if (uninterestingTags.indexOf(key) < 0) { + return true; + } + } + } + + return false; + } + + function featurePrefix(feature) { + var tags = feature.tags; + var prefix = ""; + + if (tags.boundary === "administrative") { + prefix = I18n.t("geocoder.search_osm_nominatim.admin_levels.level" + tags.admin_level) + } else { + var prefixes = I18n.t("geocoder.search_osm_nominatim.prefix"); + + for (var key in tags) { + var value = tags[key]; + + if (prefixes[key]) { + if (prefixes[key][value]) { + return prefixes[key][value]; + } else { + var first = value.substr(0, 1).toUpperCase(), + rest = value.substr(1).replace(/_/g, " "); + + return first + rest; + } + } + } + } + + if (!prefix) { + prefix = I18n.t("javascripts.query." + feature.type); + } + + return prefix; + } + + function featureName(feature) { + var tags = feature.tags; + + if (tags["name"]) { + return tags["name"]; + } else if (tags["ref"]) { + return tags["ref"]; + } else if (tags["addr:housename"]) { + return tags["addr:housename"]; + } else if (tags["addr:housenumber"] && tags["addr:street"]) { + return tags["addr:housenumber"] + " " + tags["addr:street"]; + } else { + return "#" + feature.id; + } + } + + function featureGeometry(feature) { + var geometry; + + if (feature.type === "node" && feature.lat && feature.lon) { + geometry = L.circleMarker([feature.lat, feature.lon], featureStyle); + } else if (feature.type === "way" && feature.geometry) { + geometry = L.polyline(feature.geometry.filter(function (point) { + return point !== null; + }).map(function (point) { + return [point.lat, point.lon]; + }), featureStyle); + } else if (feature.type === "relation" && feature.members) { + geometry = L.featureGroup(feature.members.map(featureGeometry).filter(function (geometry) { + return geometry !== undefined; + })); + } + + return geometry; + } + + function runQuery(latlng, radius, query, $section, compare) { + var $ul = $section.find("ul"); + + $ul.empty(); + $section.show(); + + $section.find(".loader").oneTime(1000, "loading", function () { + $(this).show(); + }); + + if ($section.data("ajax")) { + $section.data("ajax").abort(); + } + + $section.data("ajax", $.ajax({ + url: url, + method: "POST", + data: { + data: "[timeout:5][out:json];" + query, + }, + success: function(results) { + var elements; + + $section.find(".loader").stopTime("loading").hide(); + + if (compare) { + elements = results.elements.sort(compare); + } else { + elements = results.elements; + } + + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + + if (interestingFeature(element, latlng, radius)) { + var $li = $("
  • ") + .addClass("query-result") + .data("geometry", featureGeometry(element)) + .appendTo($ul); + var $p = $("

    ") + .text(featurePrefix(element) + " ") + .appendTo($li); + + $("") + .attr("href", "/" + element.type + "/" + element.id) + .text(featureName(element)) + .appendTo($p); + } + } + + if ($ul.find("li").length == 0) { + $("

  • ") + .text(I18n.t("javascripts.query.nothing_found")) + .appendTo($ul); + } + }, + error: function(xhr, status, error) { + $section.find(".loader").stopTime("loading").hide(); + + $("
  • ") + .text(I18n.t("javascripts.query." + status, { server: url, error: error })) + .appendTo($ul); + } + })); + } + + function compareSize(feature1, feature2) { + var width1 = feature1.bounds.maxlon - feature1.bounds.minlon, + height1 = feature1.bounds.maxlat - feature1.bounds.minlat, + area1 = width1 * height1, + width2 = feature2.bounds.maxlat - feature2.bounds.minlat, + height2 = feature2.bounds.maxlat - feature2.bounds.minlat, + area2 = width2 * height2; + + return area1 - area2; + } + + /* + * To find nearby objects we ask overpass for the union of the + * following sets: + * + * node(around:,,lng>) + * way(around:,,lng>) + * relation(around:,,lng>) + * + * to find enclosing objects we first find all the enclosing areas: + * + * is_in(,)->.a + * + * and then return the union of the following sets: + * + * relation(pivot.a) + * way(pivot.a) + * + * In both cases we then ask to retrieve tags and the geometry + * for each object. + */ + function queryOverpass(lat, lng) { + var latlng = L.latLng(lat, lng), + bounds = map.getBounds(), + bbox = bounds.getSouth() + "," + bounds.getWest() + "," + bounds.getNorth() + "," + bounds.getEast(), + radius = 10 * Math.pow(1.5, 19 - map.getZoom()), + around = "around:" + radius + "," + lat + "," + lng, + nodes = "node(" + around + ")", + ways = "way(" + around + ")", + relations = "relation(" + around + ")", + nearby = "(" + nodes + ";" + ways + ");out tags geom(" + bbox + ");" + relations + ";out geom(" + bbox + ");", + isin = "is_in(" + lat + "," + lng + ")->.a;way(pivot.a);out tags geom(" + bbox + ");relation(pivot.a);out tags bb;"; + + $("#sidebar_content .query-intro") + .hide(); + + if (marker) map.removeLayer(marker); + marker = L.circle(latlng, radius, featureStyle).addTo(map); + + $(document).everyTime(75, "fadeQueryMarker", function (i) { + if (i == 10) { + map.removeLayer(marker); + } else { + marker.setStyle({ + opacity: 1 - i * 0.1, + fillOpacity: 0.5 - i * 0.05 + }); + } + }, 10); + + runQuery(latlng, radius, nearby, $("#query-nearby")); + runQuery(latlng, radius, isin, $("#query-isin"), compareSize); + } + + function clickHandler(e) { + var precision = OSM.zoomPrecision(map.getZoom()), + lat = e.latlng.lat.toFixed(precision), + lng = e.latlng.lng.toFixed(precision); + + OSM.router.route("/query?lat=" + lat + "&lon=" + lng); + } + + function enableQueryMode() { + queryButton.addClass("active"); + map.on("click", clickHandler); + $(map.getContainer()).addClass("query-active"); + } + + function disableQueryMode() { + if (marker) map.removeLayer(marker); + $(map.getContainer()).removeClass("query-active").removeClass("query-disabled"); + map.off("click", clickHandler); + queryButton.removeClass("active"); + } + + var page = {}; + + page.pushstate = page.popstate = function(path) { + OSM.loadSidebarContent(path, function () { + page.load(path, true); + }); + }; + + page.load = function(path, noCentre) { + var params = querystring.parse(path.substring(path.indexOf('?') + 1)), + latlng = L.latLng(params.lat, params.lon); + + if (!window.location.hash && !noCentre && !map.getBounds().contains(latlng)) { + OSM.router.withoutMoveListener(function () { + map.setView(latlng, 15); + }); + } + + queryOverpass(params.lat, params.lon); + }; + + page.unload = function(sameController) { + if (!sameController) { + disableQueryMode(); + } + }; + + return page; +}; diff --git a/app/assets/javascripts/leaflet.query.js b/app/assets/javascripts/leaflet.query.js new file mode 100644 index 000000000..906487274 --- /dev/null +++ b/app/assets/javascripts/leaflet.query.js @@ -0,0 +1,38 @@ +L.OSM.query = function (options) { + var control = L.control(options); + + control.onAdd = function (map) { + var $container = $('
    ') + .attr('class', 'control-query'); + + var link = $('') + .attr('class', 'control-button') + .attr('href', '#') + .html('') + .appendTo($container); + + map.on('zoomend', update); + + update(); + + function update() { + var wasDisabled = link.hasClass('disabled'), + isDisabled = map.getZoom() < 14; + link + .toggleClass('disabled', isDisabled) + .attr('data-original-title', I18n.t(isDisabled ? + 'javascripts.site.queryfeature_disabled_tooltip' : + 'javascripts.site.queryfeature_tooltip')); + + if (isDisabled && !wasDisabled) { + link.trigger('disabled'); + } else if (wasDisabled && !isDisabled) { + link.trigger('enabled'); + } + } + + return $container[0]; + }; + + return control; +}; diff --git a/app/assets/javascripts/osm.js.erb b/app/assets/javascripts/osm.js.erb index 033b2de81..15c1682d5 100644 --- a/app/assets/javascripts/osm.js.erb +++ b/app/assets/javascripts/osm.js.erb @@ -8,6 +8,7 @@ OSM = { API_VERSION: <%= API_VERSION.to_json %>, STATUS: <%= STATUS.to_json %>, MAX_NOTE_REQUEST_AREA: <%= MAX_NOTE_REQUEST_AREA.to_json %>, + OVERPASS_URL: <%= OVERPASS_URL.to_json %>, apiUrl: function (object) { var url = "/api/" + OSM.API_VERSION + "/" + object.type + "/" + object.id; @@ -71,10 +72,6 @@ OSM = { mapParams.bounds = L.latLngBounds( [parseFloat(params.minlat), parseFloat(params.minlon)], [parseFloat(params.maxlat), parseFloat(params.maxlon)]); - } else if (params.lon && params.lat) { - mapParams.lon = parseFloat(params.lon); - mapParams.lat = parseFloat(params.lat); - mapParams.zoom = parseInt(params.zoom || 5); } else if (params.mlon && params.mlat) { mapParams.lon = parseFloat(params.mlon); mapParams.lat = parseFloat(params.mlat); @@ -174,5 +171,20 @@ OSM = { zoom = map.getZoom(), precision = OSM.zoomPrecision(zoom); return [center.lng.toFixed(precision), center.lat.toFixed(precision), zoom, map.getLayersCode()].join('|'); + }, + + distance: function(latlng1, latlng2) { + var lat1 = latlng1.lat * Math.PI / 180, + lng1 = latlng1.lng * Math.PI / 180, + lat2 = latlng2.lat * Math.PI / 180, + lng2 = latlng2.lng * Math.PI / 180, + latdiff = lat2 - lat1, + lngdiff = lng2 - lng1; + + return 6372795 * 2 * Math.asin( + Math.sqrt( + Math.pow(Math.sin(latdiff / 2), 2) + + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(lngdiff / 2), 2) + )); } }; diff --git a/app/assets/javascripts/router.js b/app/assets/javascripts/router.js index 9af70c21d..dcf8ea6a8 100644 --- a/app/assets/javascripts/router.js +++ b/app/assets/javascripts/router.js @@ -76,6 +76,8 @@ OSM.Router = function(map, rts) { }); } + params = params.concat(Array.prototype.slice.call(arguments, 2)); + return (controller[action] || $.noop).apply(controller, params); }; @@ -101,11 +103,12 @@ OSM.Router = function(map, rts) { if (window.history && window.history.pushState) { $(window).on('popstate', function(e) { if (!e.originalEvent.state) return; // Is it a real popstate event or just a hash change? - var path = window.location.pathname + window.location.search; + var path = window.location.pathname + window.location.search, + route = routes.recognize(path); if (path === currentPath) return; - currentRoute.run('unload'); + currentRoute.run('unload', null, route === currentRoute); currentPath = path; - currentRoute = routes.recognize(currentPath); + currentRoute = route; currentRoute.run('popstate', currentPath); map.setState(e.originalEvent.state, {animate: false}); }); @@ -114,7 +117,7 @@ OSM.Router = function(map, rts) { var path = url.replace(/#.*/, ''), route = routes.recognize(path); if (!route) return false; - currentRoute.run('unload'); + currentRoute.run('unload', null, route === currentRoute); var state = OSM.parseHash(url); map.setState(state); window.history.pushState(state, document.title, url); diff --git a/app/assets/stylesheets/common.css.scss b/app/assets/stylesheets/common.css.scss index 37a6aa7a9..35ec432b5 100644 --- a/app/assets/stylesheets/common.css.scss +++ b/app/assets/stylesheets/common.css.scss @@ -169,7 +169,7 @@ small, aside { .icon.close:hover { background-position: -200px -20px; } .icon.check { background-position: -220px 0; } .icon.note { background-position: -240px 0; } -.icon.gear { background-position: -260px 0; } +.icon.query { background-position: -260px 0; } /* Rules for links */ @@ -680,6 +680,14 @@ nav.secondary { #map { height: 100%; overflow: hidden; + + &.query-active { + cursor: help; + } + + &.query-disabled { + cursor: not-allowed; + } } #map-ui { @@ -1136,6 +1144,34 @@ header .search_form { overflow: hidden; margin: 0 0 10px 10px; } + + .query-intro p { + padding: $lineheight $lineheight $lineheight/2; + } + + .query-results { + display: none; + + h3 { + padding: $lineheight $lineheight $lineheight/2; + margin: 0; + } + + ul { + li { + padding: 15px 20px; + border-bottom: 1px solid #ddd; + + &.query-result { + cursor: pointer; + } + + &.selected { + background: #FFFFE6; + } + } + } + } } /* Rules for export sidebar */ diff --git a/app/views/browse/query.html.erb b/app/views/browse/query.html.erb new file mode 100644 index 000000000..629d84c05 --- /dev/null +++ b/app/views/browse/query.html.erb @@ -0,0 +1,22 @@ +<% set_title(t "browse.query.title") %> + +

    + + <%= t "browse.query.title" %> +

    + +
    +

    <%= t("browse.query.introduction") %>

    +
    + +
    +

    <%= t("browse.query.nearby") %>

    + <%= image_tag "searching.gif", :class => "loader" %> +
      +
      + +
      +

      <%= t("browse.query.enclosing") %>

      + <%= image_tag "searching.gif", :class => "loader" %> +
        +
        diff --git a/config/example.application.yml b/config/example.application.yml index 3fbebdc76..e7915c96b 100644 --- a/config/example.application.yml +++ b/config/example.application.yml @@ -89,6 +89,8 @@ defaults: &defaults - ".*\\.googleapis\\.com/.*" - ".*\\.google\\.com/.*" - ".*\\.google\\.ru/.*" + # URL of Overpass instance to use for feature queries + overpass_url: "//overpass-api.de/api/interpreter" development: <<: *defaults diff --git a/config/i18n-js.yml b/config/i18n-js.yml index 026ece64c..369fa340a 100644 --- a/config/i18n-js.yml +++ b/config/i18n-js.yml @@ -31,3 +31,4 @@ translations: - "*.site.sidebar.search_results" - "*.diary_entry.edit.marker_text" - "*.layouts.project_name.title" + - "*.geocoder.search_osm_nominatim.*" diff --git a/config/locales/en.yml b/config/locales/en.yml index 021151052..69e52e44d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -204,6 +204,11 @@ en: reopened_by: "Reactivated by %{user} %{when} ago" reopened_by_anonymous: "Reactivated by anonymous %{when} ago" hidden_by: "Hidden by %{user} %{when} ago" + query: + title: "Query Features" + introduction: "Click on the map to find nearby features." + nearby: "Nearby features" + enclosing: "Enclosing features" changeset: changeset_paging_nav: showing_page: "Page %{page}" @@ -521,7 +526,7 @@ en: primary_link: "Primary Road" proposed: "Proposed Road" raceway: "Raceway" - residential: "Residential" + residential: "Residential Road" rest_area: "Rest Area" road: "Road" secondary: "Secondary Road" @@ -732,6 +737,8 @@ en: tram: "Tramway" tram_stop: "Tram Stop" yard: "Railway Yard" + route: + bus: "Bus Route" shop: alcohol: "Off License" antiques: "Antiques" @@ -2126,6 +2133,8 @@ en: createnote_disabled_tooltip: Zoom in to add a note to the map map_notes_zoom_in_tooltip: Zoom in to see map notes map_data_zoom_in_tooltip: Zoom in to see map data + queryfeature_tooltip: Query features + queryfeature_disabled_tooltip: Zoom in to query features changesets: show: comment: "Comment" @@ -2145,6 +2154,13 @@ en: comment_and_resolve: Comment & Resolve comment: Comment edit_help: Move the map and zoom in on a location you want to edit, then click here. + query: + node: Node + way: Way + relation: Relation + nothing_found: No features found + error: "Error contacting %{server}: %{error}" + timeout: "Timeout contacting %{server}" redaction: edit: description: "Description" diff --git a/config/routes.rb b/config/routes.rb index 8cbf8f900..7084d1c8d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -157,6 +157,7 @@ OpenStreetMap::Application.routes.draw do match '/offline' => 'site#offline', :via => :get match '/key' => 'site#key', :via => :get match '/id' => 'site#id', :via => :get + match '/query' => 'browse#query', :via => :get match '/user/new' => 'user#new', :via => :get match '/user/new' => 'user#create', :via => :post match '/user/terms' => 'user#terms', :via => :get diff --git a/db/structure.sql b/db/structure.sql index c287baea3..343aec084 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -126,7 +126,7 @@ CREATE TYPE user_status_enum AS ENUM ( CREATE FUNCTION maptile_for_point(bigint, bigint, integer) RETURNS integer LANGUAGE c STRICT - AS '/home/ukasiu/repos/openstreetmap-website/db/functions/libpgosm', 'maptile_for_point'; + AS '/srv/www/overpass.osm.compton.nu/db/functions/libpgosm.so', 'maptile_for_point'; -- @@ -135,7 +135,7 @@ CREATE FUNCTION maptile_for_point(bigint, bigint, integer) RETURNS integer CREATE FUNCTION tile_for_point(integer, integer) RETURNS bigint LANGUAGE c STRICT - AS '/home/ukasiu/repos/openstreetmap-website/db/functions/libpgosm', 'tile_for_point'; + AS '/srv/www/overpass.osm.compton.nu/db/functions/libpgosm.so', 'tile_for_point'; -- @@ -143,8 +143,8 @@ CREATE FUNCTION tile_for_point(integer, integer) RETURNS bigint -- CREATE FUNCTION xid_to_int4(xid) RETURNS integer - LANGUAGE c STRICT - AS '/home/ukasiu/repos/openstreetmap-website/db/functions/libpgosm', 'xid_to_int4'; + LANGUAGE c IMMUTABLE STRICT + AS '/srv/www/overpass.osm.compton.nu/db/functions/libpgosm.so', 'xid_to_int4'; SET default_tablespace = ''; @@ -1795,13 +1795,6 @@ CREATE INDEX gpx_files_user_id_idx ON gpx_files USING btree (user_id); CREATE INDEX gpx_files_visible_visibility_idx ON gpx_files USING btree (visible, visibility); --- --- Name: index_changeset_comments_on_body; Type: INDEX; Schema: public; Owner: -; Tablespace: --- - -CREATE INDEX index_changeset_comments_on_body ON changeset_comments USING btree (body); - - -- -- Name: index_changeset_comments_on_created_at; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -2635,3 +2628,4 @@ INSERT INTO schema_migrations (version) VALUES ('7'); INSERT INTO schema_migrations (version) VALUES ('8'); INSERT INTO schema_migrations (version) VALUES ('9'); + diff --git a/test/javascripts/osm_test.js b/test/javascripts/osm_test.js index d7fe4a2fd..51f74fe7a 100644 --- a/test/javascripts/osm_test.js +++ b/test/javascripts/osm_test.js @@ -73,18 +73,8 @@ describe("OSM", function () { expect(params).to.have.property("bounds").deep.equal(expected); }); - it("parses lat/lon/zoom params", function () { - var params = OSM.mapParams("?lat=57.6247&lon=-3.6845"); - expect(params).to.have.property("lat", 57.6247); - expect(params).to.have.property("lon", -3.6845); - expect(params).to.have.property("zoom", 5); - - params = OSM.mapParams("?lat=57.6247&lon=-3.6845&zoom=10"); - expect(params).to.have.property("lat", 57.6247); - expect(params).to.have.property("lon", -3.6845); - expect(params).to.have.property("zoom", 10); - - params = OSM.mapParams("?mlat=57.6247&mlon=-3.6845"); + it("parses mlat/mlon/zoom params", function () { + var params = OSM.mapParams("?mlat=57.6247&mlon=-3.6845"); expect(params).to.have.property("lat", 57.6247); expect(params).to.have.property("lon", -3.6845); expect(params).to.have.property("zoom", 12); @@ -249,4 +239,14 @@ describe("OSM", function () { expect(OSM.locationCookie(map)).to.eq("-3.685|57.625|5|M"); }); }); + + describe(".distance", function () { + it("computes distance between points", function () { + var latlng1 = L.latLng(51.76712,-0.00484), + latlng2 = L.latLng(51.7675159, -0.0078329); + + expect(OSM.distance(latlng1, latlng2)).to.be.closeTo(210.664, 0.005); + expect(OSM.distance(latlng2, latlng1)).to.be.closeTo(210.664, 0.005); + }); + }); });