// Some Levenshtein-distnace code // http://www.merriampark.com/ld.htm, http://www.mgilleland.com/ld/ldjavascript.htm, Damerau–Levenshtein distance (Wikipedia) var levDist = function(s, t) { var d = [] //2d matrix // Step 1 var n = s.length var m = t.length if (n == 0) return m if (m == 0) return n // Create an array of arrays in javascript (a descending loop is quicker) for (var i = n; i >= 0; i--) d[i] = [] // Step 2 for (var i = n; i >= 0; i--) d[i][0] = i for (var j = m; j >= 0; j--) d[0][j] = j // Step 3 for (var i = 1; i <= n; i++) { var s_i = s.charAt(i - 1) // Step 4 for (var j = 1; j <= m; j++) { // Check the jagged ld total so far if (i == j && d[i][j] > 4) return n var t_j = t.charAt(j - 1) var cost = s_i == t_j ? 0 : 1 // Step 5 // Calculate the minimum var mi = d[i - 1][j] + 1 var b = d[i][j - 1] + 1 var c = d[i - 1][j - 1] + cost if (b < mi) mi = b if (c < mi) mi = c d[i][j] = mi // Step 6 // Damerau transposition if ( i > 1 && j > 1 && s_i == t.charAt(j - 2) && s.charAt(i - 2) == t_j ) { d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + cost) } } } // Step 7 return d[n][m] } var things = {} $(function() { var marker var Icon = L.icon({ iconUrl: "leaflet/images/marker-icon-red.png", iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34], shadowSize: [41, 41], shadowUrl: "leaflet/images/marker-shadow.png", }) var res = $("#result") var search = $("#searchtext") function performSearch() { var searchstring = search.val().toLowerCase() var searchresult = Object.keys(things).sort(function(a, b) { return ( levDist(searchstring, a.toLowerCase()) - levDist(searchstring, b.toLowerCase()) ) }) var html = "" for (var i = 0; i < Math.min(searchresult.length, 10); i++) { html += "
  • " + searchresult[i] + "
  • " } if (html != "") res.show() else res.hide() if (things[search]) { addMarker(things[search]) $("#btnmarker").addClass("active") setHash() } $("#result ul").html(html) $("#result ul li:first").addClass("selected") $("#result ul li").click(function() { select($(this).text()) }) res.css({ top: search.position().top + search.height() + 10, left: search.position().left, }) } function select(text) { addMarker(things[text]) $("#btnmarker").addClass("active") setHash() res.hide() } $("#searchtext").keypress(function(e) { switch (e.keyCode) { case 13: // Enter var selected = $("#result ul li.selected").first() if (selected) selected.click() break default: setTimeout(performSearch, 10) } }) var map = L.map("map", { minZoom: 0, maxZoom: 4, zoom: 2, center: [0, 0], }) L.tileLayer("/tiles/{z}/{x}/{y}.jpg", { attribution: 'Original project by blinry (source) | Source', noWrap: true, detectRetina: true, }).addTo(map) $("#btnmarker").on("click", function(event) { setTimeout(function() { var button = $(event.currentTarget) if (button.hasClass("active")) { addMarker() } else { removeMarker() } }, 0) }) setTimeout(getHash, 0) function getHash() { var hash = window.location.hash if (hash) { hash = hash.match(/([\-0-9]*)_([\-0-9]*)/) if (hash) { var pos = [ parseInt(hash[1], 10) / 1000, parseInt(hash[2], 10) / 1000, ] addMarker(pos) $("#btnmarker").addClass("active") } } } function addMarker(pos) { removeMarker() if (pos) { map.setView(pos, 2) marker = L.marker(pos, { icon: Icon, }) marker.addTo(map) } else { marker = L.marker(map.getCenter(), { draggable: true, opacity: 0.7, icon: Icon, }) marker.on("dragend", setHash) setHash() marker.addTo(map) } } function removeMarker() { if (marker) { map.removeLayer(marker) marker = false setHash() } } function setHash() { if (marker) { var pos = marker.getLatLng() pos = [ (1000 * pos.lat).toFixed(0), (1000 * pos.lng).toFixed(0), ].join("_") window.location.hash = pos } else { window.location.hash = "" } } })