diff --git a/server/app/config.go b/server/app/config.go index 2ab066d..7a64406 100644 --- a/server/app/config.go +++ b/server/app/config.go @@ -167,7 +167,7 @@ func ParseConfig(filename string) (*Config, error) { Port: 8080, EnableRendering: true, EnablePrometheus: true, - EnableSearch: false, + EnableSearch: true, EnableInitialRendering: true, EnableTransparency: false, Webdev: false, diff --git a/server/static/css/custom.css b/server/static/css/custom.css index 20f2577..f376691 100644 --- a/server/static/css/custom.css +++ b/server/static/css/custom.css @@ -18,9 +18,9 @@ body { #search-menu { position: absolute; - top: 20%; - bottom: 20%; - left: 20%; - right: 20%; + top: 5%; + bottom: 5%; + left: 5%; + right: 5%; z-index: 99999; } diff --git a/server/static/js/LayerManager.js b/server/static/js/LayerManager.js index 91756ec..4f724fe 100644 --- a/server/static/js/LayerManager.js +++ b/server/static/js/LayerManager.js @@ -1,18 +1,48 @@ /* exported LayerManager */ +/* globals RealtimeTileLayer: true */ -function LayerManager(layers, map){ +function LayerManager(wsChannel, layers, map, currentLayerId){ this.listeners = []; this.currentLayer = layers[0]; this.layers = layers; + this.map = map; + this.layerObjects = {}; var self = this; + //All layers + layers.forEach(function(layer){ + var tileLayer = new RealtimeTileLayer(wsChannel, layer.id, map); + self.layerObjects[layer.name] = tileLayer; + if (layer.id == currentLayerId){ + tileLayer.addTo(map); + self.currentLayer = layer; + } + }); + map.on('baselayerchange', function (e) { self.setLayerId(e.layer.layerId); }); } +LayerManager.prototype.switchLayer = function(layerId){ + var self = this; + Object.keys(this.layerObjects).forEach(function(key){ + var layerObj = self.layerObjects[key]; + if (self.map.hasLayer(layerObj)){ + self.map.removeLayer(layerObj); + } + }); + + Object.keys(this.layerObjects).forEach(function(key){ + var layerObj = self.layerObjects[key]; + if (layerObj.layerId == layerId){ + self.map.addLayer(layerObj); + } + }); +}; + LayerManager.prototype.setLayerId = function(layerId){ var self = this; this.layers.forEach(function(layer){ diff --git a/server/static/js/SearchControl.js b/server/static/js/SearchControl.js index 424dbec..7ec2e36 100644 --- a/server/static/js/SearchControl.js +++ b/server/static/js/SearchControl.js @@ -7,11 +7,14 @@ var SearchControl = L.Control.extend({ L.Control.prototype.initialize.call(this, opts); }, - onAdd: function() { + onAdd: function(map) { var div = L.DomUtil.create('div'); - m.mount(div, SearchInput); - m.mount(document.getElementById("search-content"), SearchMenu); + m.mount(document.getElementById("search-content"), { + view: function () { + return m(SearchMenu, {map: map}); + } + }); return div; } diff --git a/server/static/js/main.js b/server/static/js/main.js index 1d53331..53837f6 100644 --- a/server/static/js/main.js +++ b/server/static/js/main.js @@ -15,21 +15,9 @@ api.getConfig().then(function(cfg){ map.attributionControl.addAttribution('Minetest Mapserver'); - var layers = {}; var overlays = {}; - window.layerMgr = new LayerManager(cfg.layers, map); - layerMgr.setLayerId( Hashroute.getLayerId() ); - - //All layers - cfg.layers.forEach(function(layer){ - var tileLayer = new RealtimeTileLayer(wsChannel, layer.id, map); - layers[layer.name] = tileLayer; - }); - - //current layer - var currentLayer = layerMgr.getCurrentLayer(); - layers[currentLayer.name].addTo(map); + window.layerMgr = new LayerManager(wsChannel, cfg.layers, map, Hashroute.getLayerId()); //All overlays Overlaysetup(cfg, map, overlays, wsChannel, layerMgr); @@ -43,7 +31,7 @@ api.getConfig().then(function(cfg){ } //layer control - L.control.layers(layers, overlays, { position: "topright" }).addTo(map); + L.control.layers(layerMgr.layerObjects, overlays, { position: "topright" }).addTo(map); Hashroute.setup(map, layerMgr); diff --git a/server/static/js/overlays/ShopOverlay.js b/server/static/js/overlays/ShopOverlay.js index b4b7d15..cce844e 100644 --- a/server/static/js/overlays/ShopOverlay.js +++ b/server/static/js/overlays/ShopOverlay.js @@ -22,7 +22,7 @@ var ShopOverlay = AbstractIconOverlay.extend({ }, getMaxDisplayedZoom: function(){ - return 5; + return 10; }, getIcon: function(obj){ diff --git a/server/static/js/search/SearchInput.js b/server/static/js/search/SearchInput.js index 8a1817b..adaebd8 100644 --- a/server/static/js/search/SearchInput.js +++ b/server/static/js/search/SearchInput.js @@ -5,21 +5,32 @@ var SearchInput = { view: function(){ function handleInput(e){ - SearchService.search(e.target.value); + SearchStore.query = e.target.value; + } + + function handleKeyDown(e){ + if (e.keyCode == 13){ + SearchService.search(); + } + } + + function handleDoSearch(){ + SearchService.search(); } return m("div", { class: "input-group mb-3" }, [ - m("div", { class: "input-group-prepend" }, [ - m("span", { class: "input-group-text" }, [ - m("i", { class: "fa fa-search"}) - ]) - ]), m("input[type=text]", { placeholder: "Search", class: "form-control", oninput: handleInput, + onkeydown: handleKeyDown, value: SearchStore.query - }) + }), + m("div", { class: "input-group-append", onclick: handleDoSearch }, [ + m("span", { class: "input-group-text" }, [ + m("i", { class: "fa fa-search"}) + ]) + ]) ]); } }; diff --git a/server/static/js/search/SearchMenu.js b/server/static/js/search/SearchMenu.js index cd35755..f1da9d9 100644 --- a/server/static/js/search/SearchMenu.js +++ b/server/static/js/search/SearchMenu.js @@ -4,10 +4,11 @@ /* globals SearchStore: true */ var SearchMenu = { - view: function(){ + view: function(vnode){ + var style = {}; - if (!SearchStore.query) { + if (!SearchStore.show) { style.display = "none"; } @@ -15,13 +16,21 @@ var SearchMenu = { SearchService.clear(); } + function getContent(){ + if (SearchStore.busy){ + return m("div", m("i", { class: "fa fa-spinner"})); + } else { + return m(SearchResult, { map: vnode.attrs.map }); + } + } + return m("div", { class: "card", id: "search-menu", style: style }, [ m("div", { class: "card-header" }, [ m("i", { class: "fa fa-search"}), "Search", m("i", { class: "fa fa-times float-right", onclick: close }), ]), - m("div", { class: "card-body", style: {overflow: "auto"} }, m(SearchResult)) + m("div", { class: "card-body", style: {overflow: "auto"} }, getContent()) ]); } }; diff --git a/server/static/js/search/SearchResult.js b/server/static/js/search/SearchResult.js index e34cece..d7da451 100644 --- a/server/static/js/search/SearchResult.js +++ b/server/static/js/search/SearchResult.js @@ -3,7 +3,8 @@ /* globals layerMgr: true */ var SearchResult = { - view: function(){ + view: function(vnode){ + var map = vnode.attrs.map; function getLayer(obj){ var layer = layerMgr.getLayerByY(obj.y); @@ -11,31 +12,88 @@ var SearchResult = { } function getPos(obj){ - var layer = layerMgr.getLayerByY(obj.y); - var link = (layer ? layer.id : "0") + "/" + obj.x + "/" + obj.z + "/" + 12; var text = obj.x + "/" + obj.y + "/" + obj.z; - return m("a", { href: "#" + link }, text); + return m("span", {class:"badge badge-success"}, text); } var rows = SearchStore.result.map(function(obj){ - return m("tr", [ - m("td", obj.type), + + var row_classes = ""; + var description = obj.type; + var type = obj.type; + + if (obj.type == "train"){ + description = [ + m("span", obj.attributes.station), + " ", + m("span", {class:"badge badge-info"}, obj.attributes.line) + ]; + + type = m("i", { class: "fa fa-subway" }); + } + + if (obj.type == "travelnet"){ + description = m("span", obj.attributes.station_name); + type = m("img", { src: "pics/travelnet_inv.png" }); + } + + if (obj.type == "poi"){ + description = m("span", obj.attributes.name); + type = m("img", { src: "css/images/marker-icon.png" }); + } + + if (obj.type == "shop") { + if (obj.attributes.stock == 0){ + row_classes += "table-warning"; + type = m("img", { src: "pics/shop_empty.png" }); + } else { + type = m("img", { src: "pics/shop.png" }); + } + + description = m("span", [ + "Shop, trading ", + m("span", {class:"badge badge-primary"}, obj.attributes.out_count + "x"), + m("span", {class:"badge badge-info"}, obj.attributes.out_item), + " for ", + m("span", {class:"badge badge-primary"}, obj.attributes.in_count + "x"), + m("span", {class:"badge badge-info"}, obj.attributes.in_item), + " Stock: ", + m("span", {class:"badge badge-info"}, obj.attributes.stock) + ]); + } + + function onclick(){ + var layer = layerMgr.getLayerByY(obj.y); + + layerMgr.switchLayer(layer.id); + + map.setView([obj.z, obj.x], 12); + SearchStore.show = false; + } + + return m("tr", {"class": row_classes}, [ + m("td", type), m("td", obj.attributes.owner), m("td", getLayer(obj)), m("td", getPos(obj)), - m("td", "stuff") + m("td", description), + m("button[type=button]", {class: "btn btn-secondary", onclick: onclick }, [ + "Goto ", + m("i", { class: "fas fa-play" }) + ]) ]); }); - return m("table", {class:"table"}, [ + return m("table", {class:"table table-striped"}, [ m("thead", [ m("tr", [ m("th", "Type"), m("th", "Owner"), m("th", "Layer"), m("th", "Position"), - m("th", "Description") + m("th", "Description"), + m("th", "Action") ]) ]), m("tbody", rows) diff --git a/server/static/js/search/SearchService.js b/server/static/js/search/SearchService.js index 32a4415..7cf61e8 100644 --- a/server/static/js/search/SearchService.js +++ b/server/static/js/search/SearchService.js @@ -3,37 +3,55 @@ var SearchService = { - search: function(q){ - SearchStore.query = q; - + search: function(){ + SearchStore.show = true; this.fetchData(); }, - fetchData: debounce(function(){ + fetchData: function(){ SearchStore.result = []; if (!SearchStore.query){ return; } - api.getMapObjects({ - pos1: { x:-2048, y:-2048, z:-2048 }, - pos2: { x:2048, y:2048, z:2048 }, - type: "shop", - attributelike: { - key: "out_item", - value: "%" + SearchStore.query + "%" - } - }) - .then(function(result){ - SearchStore.result = result; - //console.log(result); //XXX + SearchStore.busy = true; + + function searchFor(type, key, valuelike){ + return api.getMapObjects({ + pos1: { x:-2048, y:-2048, z:-2048 }, + pos2: { x:2048, y:2048, z:2048 }, + type: type, + attributelike: { + key: key, + value: "%" + valuelike +"%" + } + }); + } + + var prom_list = []; + + prom_list.push(searchFor("shop", "out_item", SearchStore.query)); + prom_list.push(searchFor("poi", "name", SearchStore.query)); + prom_list.push(searchFor("train", "station", SearchStore.query)); + prom_list.push(searchFor("travelnet", "station_name", SearchStore.query)); + + Promise.all(prom_list) + .then(function(results){ + + var arr = []; + results.forEach(function(r) { + arr = arr.concat(r); + }); + + SearchStore.result = arr; + SearchStore.busy = false; }); - }, 400), + }, clear: function(){ - SearchStore.query = ""; SearchStore.result = []; + SearchStore.show = false; } }; diff --git a/server/static/js/search/SearchStore.js b/server/static/js/search/SearchStore.js index 656d4e6..397abb0 100644 --- a/server/static/js/search/SearchStore.js +++ b/server/static/js/search/SearchStore.js @@ -2,5 +2,7 @@ var SearchStore = { query: "", + show: false, + busy: false, result: [] };