Show markers and popups for search results

pull/54/merge
Candid Dauth 2016-10-11 14:28:16 +03:00
rodzic 1feb17b39c
commit 9ec78c79f8
8 zmienionych plików z 211 dodań i 36 usunięć

Wyświetl plik

@ -13,6 +13,7 @@ var FacilPad = {
});
fp.app.constant("L", L);
fp.app.constant("linkifyStr", linkifyStr);
// Dereferrer
$(document).on("click", "a", function(e) {

Wyświetl plik

@ -140,15 +140,18 @@
var listener = map.addClickListener(function(pos) {
message.close();
map.socket.emit("addMarker", { lon: pos.lon, lat: pos.lat, typeId: type.id }, function(err, marker) {
if(err)
return map.messages.showMessage("danger", err);
markersUi.createMarker(pos, type);
});
},
createMarker: function(pos, type, properties) {
map.socket.emit("addMarker", $.extend({ lon: pos.lon, lat: pos.lat, typeId: type.id }, properties), function(err, marker) {
if(err)
return map.messages.showMessage("danger", err);
markersUi._addMarker(marker);
markersUi._addMarker(marker);
markersById[marker.id].openPopup();
markersUi.editMarker(marker);
});
markersById[marker.id].openPopup();
markersUi.editMarker(marker);
});
}
};

Wyświetl plik

@ -0,0 +1,21 @@
<div class="content container-fluid">
<h2>{{result.short_name}}</h2>
<p ng-if="result.display_name != result.short_name">{{result.display_name}} ({{result.type}})</p>
<p ng-if="result.display_name == result.short_name">{{result.type}}</p>
<dl class="dl-horizontal">
<dt class="pos" ng-if="result.type != 'coordinates'">Coordinates</dt>
<dd class="pos" ng-if="result.type != 'coordinates'">{{round(result.lat, 5)}}, {{round(result.lon, 5)}}</dd>
<dt ng-repeat-start="(key, value) in result.extratags">{{key}}</dt>
<dd ng-repeat-end ng-bind-html="value | fpRenderOsmTag:key">{{value}}</dd>
</dl>
</div>
<div class="buttons" ng-if="!readonly">
<div uib-dropdown ng-if="(types | fpPropertyCount:{type:'marker'}) > 1">
<button id="add-type-button" type="button" class="btn btn-default" uib-dropdown-toggle>Add to map <span class="caret"></span></button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="add-type-button" uib-dropdown-menu>
<li role="menuitem" ng-repeat="type in types | fpObjectFilter:{type:'marker'}"><a href="#" ng-click="addToMap(type)">{{type.name}}</a></li>
</ul>
</div>
<button ng-if="(types | fpPropertyCount:{type:'marker'}) == 1" class="btn btn-default" ng-click="addToMap()">Add to map</button>
</div>

Wyświetl plik

@ -20,5 +20,8 @@
</li>
</ul>
</div>
<div class="fp-search-buttons" ng-show="searchResults.length > 1">
<button class="btn btn-default" ng-model="showAll" uib-btn-checkbox>Show all</button>
</div>
</div>
</div>

Wyświetl plik

@ -1,46 +1,161 @@
(function(fp, $, ng, undefined) {
fp.app.factory("fpMapSearch", function($rootScope, $templateCache, $compile, fpUtils) {
fp.app.factory("fpMapSearch", function($rootScope, $templateCache, $compile, fpUtils, L, $timeout) {
return function(map) {
var iconSuffix = ".n.32.png";
var scope = $rootScope.$new(true);
scope.searchString = "";
scope.searchResults = null;
scope.showAll = false;
scope.activeResult = null;
scope.search = function() {
fpMapSearch.search();
scope.searchResults = null;
clearRenders();
if(scope.searchString.trim() != "") {
map.loadStart();
map.socket.emit("find", { query: scope.searchString }, function(err, results) {
map.loadEnd();
if(err)
map.messages.showMessage("danger", err);
scope.searchResults = results;
if(results && results.length > 0)
scope.showAll ? scope.showAllResults() : scope.showResult(results[0]);
});
}
};
scope.showResult = function(result) {
if(result.boundingbox)
map.map.flyToBounds([ [ result.boundingbox[0], result.boundingbox[3 ] ], [ result.boundingbox[1], result.boundingbox[2] ] ]);
else
map.map.flyTo([ result.lat, result.lon ], result.zoom);
if(scope.showAll) {
map.map.flyToBounds(layerGroup.getBounds());
result.marker.openPopup();
} else {
clearRenders();
renderResult(result, true);
if(result.boundingbox)
map.map.flyToBounds([ [ result.boundingbox[0], result.boundingbox[3 ] ], [ result.boundingbox[1], result.boundingbox[2] ] ]);
else
map.map.flyTo([ result.lat, result.lon ], result.zoom);
}
};
scope.showAllResults = function() {
clearRenders();
for(var i=0; i<scope.searchResults.length; i++)
renderResult(scope.searchResults[i], false);
map.map.flyToBounds(layerGroup.getBounds());
};
scope.$watch("showAll", function() {
if(!scope.searchResults)
return;
if(scope.showAll)
scope.showAllResults();
else if(scope.searchResults.length > 0)
scope.showResult(scope.activeResult || scope.searchResults[0]);
});
var el = $($templateCache.get("map/search/search.html")).insertAfter(map.map.getContainer());
$compile(el)(scope);
scope.$evalAsync(); // $compile only replaces variables on next digest
var layerGroup = L.featureGroup([]).addTo(map.map);
function renderResult(result, showPopup) {
layerGroup.addLayer(
L.geoJson(result.geojson, {
pointToLayer: function(geoJsonPoint, latlng) {
return null;
}
})
.bindPopup($("<div/>")[0], map.popupOptions)
.on("popupopen", function(e) {
scope.activeResult = result;
renderResultPopup(result, e.popup);
})
.on("popupclose", function(e) {
scope.activeResult = null;
ng.element(e.popup.getContent()).scope().$destroy();
})
.bindTooltip(result.display_name, $.extend({}, map.tooltipOptions))
);
result.marker = L.marker([ result.lat, result.lon ], {
icon: L.icon({
iconUrl: result.icon.replace(/\.[a-z]+\.[0-9]+\.png$/, iconSuffix),
iconSize: [ 32, 32 ],
iconAnchor: [ 16, 16 ],
popupAnchor: [ 0, -16 ]
})
})
.bindPopup($("<div/>")[0], map.popupOptions)
.on("popupopen", function(e) {
scope.activeResult = result;
renderResultPopup(result, e.popup);
})
.on("popupclose", function(e) {
scope.activeResult = null;
ng.element(e.popup.getContent()).scope().$destroy();
})
.bindTooltip(result.display_name, $.extend({}, map.tooltipOptions, { offset: [ 20, 0 ] }));
layerGroup.addLayer(result.marker);
if(showPopup)
result.marker.openPopup();
}
function clearRenders() {
layerGroup.clearLayers();
}
function renderResultPopup(result, popup) {
var scope = map.socket.$new();
scope.result = result;
scope.addToMap = function(type) {
if(type == null) {
for(var i in map.socket.types) {
if(map.socket.types[i].type == "marker") {
type = map.socket.types[i];
break;
}
}
}
map.markersUi.createMarker(result, type, { name: result.display_name });
};
var el = popup.getContent();
$(el).html($templateCache.get("map/search/result-popup.html"));
$compile(el)(scope);
// Prevent popup close on button click
$("button", el).click(function(e) {
e.preventDefault();
});
$timeout(function() { $timeout(function() { // $compile only replaces variables on next digest
popup.update();
}); });
}
var fpMapSearch = {
search: function(query) {
if(query != null)
scope.searchString = query;
scope.searchResults = null;
if(scope.searchString.trim() != "") {
map.loadStart();
map.socket.emit("find", { query: scope.searchString }, function(err, results) {
map.loadEnd();
if(err)
map.messages.showMessage("danger", err);
scope.searchResults = results;
if(results.length > 0)
scope.showResult(results[0]);
});
}
scope.search();
},
showFiles: function(files) {

Wyświetl plik

@ -31,7 +31,7 @@
};
fpUtils.createMarkerIcon = function(colour, huge) {
return new L.Icon({
return L.icon({
iconUrl: fpUtils.createMarkerGraphic(colour, huge),
iconSize: huge ? [10000, 10000] : [21, 25],
iconAnchor: huge ? [5010, 5025] : [10, 25],
@ -218,4 +218,23 @@
};
});
fp.app.filter('fpRenderOsmTag', function($sce, linkifyStr, fpUtils) {
return function(value, key) {
if(key.match(/^wikipedia(:|$)/)) {
return $sce.trustAsHtml(value.split(";").map(function(it) {
var m = it.match(/^(\s*)((([-a-z]+):)?(.*))(\s*)$/);
var url = "https://" + (m[4] || "en") + ".wikipedia.org/wiki/" + m[5];
return m[1] + '<a href="' + fpUtils.quoteHtml(url) + '" target="_blank">' + fpUtils.quoteHtml(m[2]) + '</a>' + m[6];
}).join(";"));
} else if(key.match(/^wikidata(:|$)/)) {
return $sce.trustAsHtml(value.split(";").map(function(it) {
var m = it.match(/^(\s*)(.*?)(\s*)$/);
return m[1] + '<a href="https://www.wikidata.org/wiki/' + fpUtils.quoteHtml(m[2]) + '" target="_blank">' + fpUtils.quoteHtml(m[2]) + '</a>' + m[3];
}).join(";"));
} else {
return $sce.trustAsHtml(linkifyStr(value));
}
};
});
})(FacilPad, jQuery, angular);

Wyświetl plik

@ -26,7 +26,8 @@
"bootstrap-touchspin": "^3.1.2",
"leaflet": "^1.0.1",
"leaflet-geometry-util": "https://github.com/makinacorpus/Leaflet.GeometryUtil/raw/master/src/leaflet.geometryutil.js",
"leaflet-almostover": "https://github.com/makinacorpus/Leaflet.AlmostOver/raw/gh-pages/src/leaflet.almostover.js"
"leaflet-almostover": "https://github.com/makinacorpus/Leaflet.AlmostOver/raw/gh-pages/src/leaflet.almostover.js",
"linkifyjs": "^2.1.3"
},
"overrides": {
"bootstrap": {
@ -36,6 +37,12 @@
"dist/js/bootstrap.js",
"dist/fonts/glyphicons-halflings-regular.ttf"
]
},
"linkifyjs": {
"main": [
"linkify.js",
"linkify-string.js"
]
}
}
}

Wyświetl plik

@ -51,14 +51,16 @@ function find(query, callback) {
lat: lonlat.lat,
lon : lonlat.lon,
type : "coordinates",
short_name: lonlat.lat + ", " + lonlat.lon,
display_name : lonlat.lat + ", " + lonlat.lon,
zoom: lonlat.zoom
zoom: lonlat.zoom,
icon: "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png"
} ];
return callback(null, results);
}
request({
url: nameFinderUrl + "?format=jsonv2&polygon_geojson=1&addressdetails=1&limit=" + encodeURIComponent(limit) + "&extratags=1&q=" + encodeURIComponent(query),
url: nameFinderUrl + "?format=jsonv2&polygon_geojson=1&addressdetails=1&namedetails=1&limit=" + encodeURIComponent(limit) + "&extratags=1&q=" + encodeURIComponent(query),
json: true
}, function(err, response, body) {
if(err)
@ -68,13 +70,17 @@ function find(query, callback) {
var results = [ ];
body.forEach(function(result) {
var displayName = makeDisplayName(result);
results.push({
display_name: makeDisplayName(result),
short_name: displayName.split(',')[0],
display_name: displayName,
boundingbox: result.boundingbox,
lat: result.lat,
lon: result.lon,
extratags: result.extratags,
geojson: result.geojson,
icon: result.icon,
type: result.type,
icon: result.icon || "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png",
type: result.type == "yes" ? result.category : result.type,
osm_id: result.osm_id,
osm_type: result.osm_type
});
@ -95,7 +101,7 @@ function makeDisplayName(result) {
// address notation guidelines
var type = result.type;
var name = result.address[result.type] || result.display_name.split(',')[0] || "";
var name = result.namedetails.name;
var countryCode = result.address.country_code;
var road = result.address.road;