Add search, a few flow updates

This commit is contained in:
Pieter Vander Vennet 2020-07-01 02:12:33 +02:00
parent 7b9ab77bda
commit c87c014045
14 changed files with 345 additions and 17 deletions

View file

@ -191,9 +191,15 @@ export class FilteredLayer {
layer.on("click", function(e) { layer.on("click", function(e) {
console.log("Selected ", feature) console.log("Selected ", feature)
self._selectedElement.setData(feature.properties); self._selectedElement.setData(feature.properties);
L.DomEvent.stop(e); // Marks the event as consumed L.DomEvent.stop(e); // Marks the event as consumed
const uiElement = self._showOnPopup.data(); const uiElement = self._showOnPopup.data();
layer.bindPopup(uiElement.Render()).openPopup(); const popup = L.popup();
popup.setContent(uiElement.Render());
layer.bindPopup(popup).openPopup();
popup.onclose(() => {
layer.removePopup(popup)
});
uiElement.Update(); uiElement.Update();
uiElement.Activate(); uiElement.Activate();

18
Logic/Geocoding.ts Normal file
View file

@ -0,0 +1,18 @@
import * as $ from "jquery"
import {UIEventSource} from "../UI/UIEventSource";
export class Geocoding {
private static readonly host = "https://nominatim.openstreetmap.org/search?";
static Search(query: string, currentLocation: UIEventSource<{ lat: number, lon: number }>,
handleResult: ((places: { display_name: string, lat: number, lon: number, boundingbox : number[] }[]) => void)) {
$.getJSON(
Geocoding.host + "format=json&accept-language=nl&q=" + query,
function (data) {
handleResult(data);
});
}
}

View file

@ -24,6 +24,7 @@ export class StrayClickHandler {
const self = this; const self = this;
const map = basemap.map; const map = basemap.map;
basemap.LastClickLocation.addCallback(function (lastClick) { basemap.LastClickLocation.addCallback(function (lastClick) {
selectElement.setData(undefined);
if (self._lastMarker !== undefined) { if (self._lastMarker !== undefined) {
map.removeLayer(self._lastMarker); map.removeLayer(self._lastMarker);
@ -36,8 +37,9 @@ export class StrayClickHandler {
self._lastMarker.addTo(map); self._lastMarker.addTo(map);
self._lastMarker.bindPopup(popup).openPopup(); self._lastMarker.bindPopup(popup).openPopup();
self._lastMarker.on("click", () => {
leftMessage.setData(self._uiToShow); leftMessage.setData(self._uiToShow);
});
}); });

View file

@ -75,5 +75,8 @@ Images from Wikipedia/Wikimedia
https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg
Camera Icon, Dave Gandy, CC-BY-SA 3.0 Camera Icon, Dave Gandy, CC-BY-SA 3.0
https://commons.wikimedia.org/wiki/File:OOjs_UI_indicator_search-rtl.svg
Search Icon, MIT
https://commons.wikimedia.org/wiki/File:Home-icon.svg https://commons.wikimedia.org/wiki/File:Home-icon.svg
Home icon by Timothy Miller, CC-BY-SA 3.0 Home icon by Timothy Miller, CC-BY-SA 3.0

46
UI/Base/TextField.ts Normal file
View file

@ -0,0 +1,46 @@
import {UIElement} from "../UIElement";
import {UIEventSource} from "../UIEventSource";
export class TextField extends UIElement {
public value = new UIEventSource("");
/**
* Pings and has the value data
*/
public enterPressed = new UIEventSource<string>(undefined);
private _placeholder: UIEventSource<string>;
constructor(placeholder : UIEventSource<string>) {
super(placeholder);
this._placeholder = placeholder;
}
protected InnerRender(): string {
return "<form onSubmit='return false' class='form-text-field'>" +
"<input type='text' placeholder='"+this._placeholder.data+"' id='text-" + this.id + "'>" +
"</form>";
}
InnerUpdate(htmlElement: HTMLElement) {
super.InnerUpdate(htmlElement);
const field = document.getElementById('text-' + this.id);
const self = this;
field.oninput = () => {
self.value.setData(field.value);
};
field.addEventListener("keyup", function (event) {
if (event.key === "Enter") {
self.enterPressed.setData(field.value);
}
});
}
Clear() {
const field = document.getElementById('text-' + this.id);
if (field !== undefined) {
field.value = "";
}
}
}

73
UI/SearchAndGo.ts Normal file
View file

@ -0,0 +1,73 @@
import {UIElement} from "./UIElement";
import {TextField} from "./Base/TextField";
import {VariableUiElement} from "./Base/VariableUIElement";
import {UIEventSource} from "./UIEventSource";
import {FixedUiElement} from "./Base/FixedUiElement";
import {Geocoding} from "../Logic/Geocoding";
import {Basemap} from "../Logic/Basemap";
import {VerticalCombine} from "./Base/VerticalCombine";
export class SearchAndGo extends UIElement {
private _placeholder = new UIEventSource("Ga naar een locatie...")
private _searchField = new TextField(this._placeholder);
private _foundEntries = new UIEventSource([]);
private _map: Basemap;
private _goButton = new FixedUiElement("<img class='search-go' src='./assets/search.svg' alt='GO'>");
constructor(map: Basemap) {
super(undefined);
this._map = map;
this.ListenTo(this._foundEntries);
const self = this;
this._searchField.enterPressed.addCallback(() => {
self.RunSearch();
});
this._goButton.onClick(function () {
self.RunSearch();
});
}
// Triggered by 'enter' or onclick
private RunSearch() {
const searchString = this._searchField.value.data;
this._searchField.Clear();
this._placeholder.setData("Bezig met zoeken...");
const self = this;
Geocoding.Search(searchString, undefined, (result) => {
const bb = result[0].boundingbox;
const bounds = [
[bb[0], bb[2]],
[bb[1], bb[3]]
]
self._map.map.fitBounds(bounds);
this._placeholder.setData("Ga naar locatie...");
});
}
protected InnerRender(): string {
// "<img class='search' src='./assets/search.svg' alt='Search'> " +
return this._goButton.Render() +
this._searchField.Render();
}
Update() {
super.Update();
this._searchField.Update();
this._goButton.Update();
}
Activate() {
super.Activate();
this._searchField.Activate();
this._goButton.Activate();
}
}

View file

@ -1,4 +1,5 @@
import {UIEventSource} from "./UIEventSource"; import {UIEventSource} from "./UIEventSource";
import {Playground} from "../Layers/Playground";
export abstract class UIElement { export abstract class UIElement {
@ -18,7 +19,7 @@ export abstract class UIElement {
protected ListenTo(source: UIEventSource<any>) { protected ListenTo(source: UIEventSource<any>) {
if(source === undefined){ if (source === undefined) {
return; return;
} }
const self = this; const self = this;
@ -27,6 +28,13 @@ export abstract class UIElement {
}) })
} }
private _onClick: () => void;
public onClick(f: (() => void)) {
this._onClick = f;
this.Update();
}
Update(): void { Update(): void {
let element = document.getElementById(this.id); let element = document.getElementById(this.id);
if (element === null || element === undefined) { if (element === null || element === undefined) {
@ -35,14 +43,24 @@ export abstract class UIElement {
} }
element.innerHTML = this.InnerRender(); element.innerHTML = this.InnerRender();
if(this._hideIfEmpty){ if (this._hideIfEmpty) {
if(element.innerHTML === ""){ if (element.innerHTML === "") {
element.parentElement.style.display = "none"; element.parentElement.style.display = "none";
}else{ } else {
element.parentElement.style.display = undefined; element.parentElement.style.display = undefined;
} }
} }
if (this._onClick !== undefined) {
console.log("Registering")
const self = this;
element.onclick = () => {
console.log("Clicked!")
self._onClick();
}
element.style.cursor = "pointer";
}
this.InnerUpdate(element); this.InnerUpdate(element);
} }

View file

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
viewBox="0 0 26.458333 26.458334"
version="1.1"
id="svg8"
sodipodi:docname="arrow-right-go-black.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="46.174919"
inkscape:cy="90.659821"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1001"
inkscape:window-x="0"
inkscape:window-y="1050"
inkscape:window-maximized="1">
<sodipodi:guide
position="13.229167,23.859748"
orientation="1,0"
id="guide815"
inkscape:locked="false" />
<sodipodi:guide
position="14.944824,13.229167"
orientation="0,1"
id="guide817"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-270.54165)">
<path
style="fill:none;stroke:#000000;stroke-width:3.69714379;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 13.091004,274.74719 c 0,0 8.270349,6.58048 8.299659,9.04335 0.02932,2.46286 -8.299659,9.0653 -8.299659,9.0653"
id="path821"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:3.4395833;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 21.297864,283.77082 H 5.4219634 v 0"
id="path815"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

6
assets/search.svg Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<g id="search">
<path id="magnifying-glass" d="M1.63 9.474L4.006 7.1l.17-.1a3.45 3.45 0 0 1-.644-2.01A3.478 3.478 0 1 1 7.01 8.47 3.43 3.43 0 0 1 5 7.822l-.098.17-2.375 2.373c-.19.188-.543.142-.79-.105s-.293-.6-.104-.79zm5.378-2.27A2.21 2.21 0 1 0 4.8 4.994 2.21 2.21 0 0 0 7.01 7.21z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 422 B

View file

@ -122,12 +122,60 @@ body {
-webkit-border-radius: 2em; -webkit-border-radius: 2em;
-moz-border-radius: 2em; -moz-border-radius: 2em;
border-radius: 2em; border-radius: 2em;
border-bottom-right-radius: 1.5em;
border-top-right-radius: 1.5em;
transition: all 500ms linear; transition: all 500ms linear;
margin: 1em; margin: 0;
margin-left: 0; margin-bottom: 0.5em;
margin-top: 0;
min-width: 20em; min-width: 20em;
pointer-events: all; pointer-events: all;
}
#userbadge-and-search {
display: inline-block;
}
#searchbox {
display: inline-block;
text-align: left;
background-color: white;
transition: all 500ms linear;
pointer-events: all;
border-radius: 1.3em;
margin: 0;
margin-bottom: 1em;
width: 100%;
}
.search {
position: relative;
float: left;
height: 2em;
margin-right: 0.5em;
}
#searchbox .form-text-field {
position: relative;
float: left;
margin-top: 0.2em;
}
#searchbox input[type="text"] {
background: transparent;
border: none;
font-size: large;
}
.search-go {
position: relative;
height: 1.2em;
border: 2px solid black;
border-radius: 2em;
padding: 0.4em;
float: left;
margin-right: 0.5em;
} }
@ -159,7 +207,8 @@ body {
#welcomeMessage { #welcomeMessage {
display: inline-block; display: inline-block;
max-width: 30em; max-width: 30em;
padding: 1em; padding: 0;
padding-bottom: 1em;
} }
#messagesboxmobilewrapper { #messagesboxmobilewrapper {

View file

@ -21,8 +21,13 @@
</div> </div>
<div id="topleft-tools"> <div id="topleft-tools">
<div id="userbadge-and-search">
<div id="userbadge"> <div id="userbadge">
Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is blocking it. Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is
blocking it.
</div>
<br/>
<div id="searchbox"></div>
</div> </div>
<br/> <br/>
<div id="messagesbox"> <div id="messagesbox">

View file

@ -19,6 +19,7 @@ import {GeoLocationHandler} from "./Logic/GeoLocationHandler";
import {StrayClickHandler} from "./Logic/StrayClickHandler"; import {StrayClickHandler} from "./Logic/StrayClickHandler";
import {SimpleAddUI} from "./UI/SimpleAddUI"; import {SimpleAddUI} from "./UI/SimpleAddUI";
import {VariableUiElement} from "./UI/Base/VariableUIElement"; import {VariableUiElement} from "./UI/Base/VariableUIElement";
import {SearchAndGo} from "./UI/SearchAndGo";
let dryRun = false; let dryRun = false;
@ -182,6 +183,8 @@ const pendingChanges = new PendingChanges(
new UserBadge(osmConnection.userDetails, pendingChanges, bm) new UserBadge(osmConnection.userDetails, pendingChanges, bm)
.AttachTo('userbadge'); .AttachTo('userbadge');
new SearchAndGo(bm).AttachTo("searchbox");
var welcomeMessage = () => { var welcomeMessage = () => {
return new VariableUiElement( return new VariableUiElement(
osmConnection.userDetails.map((userdetails) => { osmConnection.userDetails.map((userdetails) => {

View file

@ -5,7 +5,8 @@
<link href="index.css" rel="stylesheet"/> <link href="index.css" rel="stylesheet"/>
</head> </head>
<body> <body>
<div id="maindiv"e>Hello World</div> <div id="maindiv">'maindiv' not attached</div>
<div id="extradiv">'extradiv' not attached</div>
<script src="./test.ts"></script> <script src="./test.ts"></script>
</body> </body>
</html> </html>

17
test.ts
View file

@ -0,0 +1,17 @@
import {Geocoding} from "./Logic/Geocoding";
import {SearchAndGo} from "./UI/SearchAndGo";
import {TextField} from "./UI/Base/TextField";
import {VariableUiElement} from "./UI/Base/VariableUIElement";
console.log("HI");
new SearchAndGo().AttachTo("maindiv");
/*const tf = new TextField();
tf.AttachTo("maindiv");
tf.enterPressed.addCallback(() => {alert("Searching")});
new VariableUiElement(tf.value).AttachTo("extradiv");
/*/
//*/