Add search, a few flow updates
This commit is contained in:
parent
7b9ab77bda
commit
c87c014045
14 changed files with 345 additions and 17 deletions
|
@ -191,9 +191,15 @@ export class FilteredLayer {
|
|||
layer.on("click", function(e) {
|
||||
console.log("Selected ", feature)
|
||||
self._selectedElement.setData(feature.properties);
|
||||
|
||||
L.DomEvent.stop(e); // Marks the event as consumed
|
||||
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.Activate();
|
||||
|
||||
|
|
18
Logic/Geocoding.ts
Normal file
18
Logic/Geocoding.ts
Normal 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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -24,6 +24,7 @@ export class StrayClickHandler {
|
|||
const self = this;
|
||||
const map = basemap.map;
|
||||
basemap.LastClickLocation.addCallback(function (lastClick) {
|
||||
selectElement.setData(undefined);
|
||||
|
||||
if (self._lastMarker !== undefined) {
|
||||
map.removeLayer(self._lastMarker);
|
||||
|
@ -36,8 +37,9 @@ export class StrayClickHandler {
|
|||
self._lastMarker.addTo(map);
|
||||
self._lastMarker.bindPopup(popup).openPopup();
|
||||
|
||||
|
||||
leftMessage.setData(self._uiToShow);
|
||||
self._lastMarker.on("click", () => {
|
||||
leftMessage.setData(self._uiToShow);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -75,5 +75,8 @@ Images from Wikipedia/Wikimedia
|
|||
https://commons.wikimedia.org/wiki/File:Camera_font_awesome.svg
|
||||
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
|
||||
Home icon by Timothy Miller, CC-BY-SA 3.0
|
||||
|
|
46
UI/Base/TextField.ts
Normal file
46
UI/Base/TextField.ts
Normal 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
73
UI/SearchAndGo.ts
Normal 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();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import {UIEventSource} from "./UIEventSource";
|
||||
import {Playground} from "../Layers/Playground";
|
||||
|
||||
export abstract class UIElement {
|
||||
|
||||
|
@ -18,7 +19,7 @@ export abstract class UIElement {
|
|||
|
||||
|
||||
protected ListenTo(source: UIEventSource<any>) {
|
||||
if(source === undefined){
|
||||
if (source === undefined) {
|
||||
return;
|
||||
}
|
||||
const self = this;
|
||||
|
@ -27,22 +28,39 @@ export abstract class UIElement {
|
|||
})
|
||||
}
|
||||
|
||||
private _onClick: () => void;
|
||||
|
||||
public onClick(f: (() => void)) {
|
||||
this._onClick = f;
|
||||
this.Update();
|
||||
}
|
||||
|
||||
Update(): void {
|
||||
let element = document.getElementById(this.id);
|
||||
let element = document.getElementById(this.id);
|
||||
if (element === null || element === undefined) {
|
||||
// The element is not painted
|
||||
return;
|
||||
}
|
||||
|
||||
element.innerHTML = this.InnerRender();
|
||||
if(this._hideIfEmpty){
|
||||
if(element.innerHTML === ""){
|
||||
if (this._hideIfEmpty) {
|
||||
if (element.innerHTML === "") {
|
||||
element.parentElement.style.display = "none";
|
||||
}else{
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
81
assets/arrow-right-go-black.svg
Normal file
81
assets/arrow-right-go-black.svg
Normal 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
6
assets/search.svg
Normal 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 |
57
index.css
57
index.css
|
@ -122,12 +122,60 @@ body {
|
|||
-webkit-border-radius: 2em;
|
||||
-moz-border-radius: 2em;
|
||||
border-radius: 2em;
|
||||
border-bottom-right-radius: 1.5em;
|
||||
border-top-right-radius: 1.5em;
|
||||
transition: all 500ms linear;
|
||||
margin: 1em;
|
||||
margin-left: 0;
|
||||
margin-top: 0;
|
||||
margin: 0;
|
||||
margin-bottom: 0.5em;
|
||||
|
||||
min-width: 20em;
|
||||
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 {
|
||||
display: inline-block;
|
||||
max-width: 30em;
|
||||
padding: 1em;
|
||||
padding: 0;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
#messagesboxmobilewrapper {
|
||||
|
|
|
@ -21,8 +21,13 @@
|
|||
</div>
|
||||
|
||||
<div id="topleft-tools">
|
||||
<div id="userbadge">
|
||||
Loading... If this message persists, check if javascript is enabled and if no extension (uMatrix) is blocking it.
|
||||
<div id="userbadge-and-search">
|
||||
<div id="userbadge">
|
||||
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>
|
||||
<br/>
|
||||
<div id="messagesbox">
|
||||
|
|
3
index.ts
3
index.ts
|
@ -19,6 +19,7 @@ import {GeoLocationHandler} from "./Logic/GeoLocationHandler";
|
|||
import {StrayClickHandler} from "./Logic/StrayClickHandler";
|
||||
import {SimpleAddUI} from "./UI/SimpleAddUI";
|
||||
import {VariableUiElement} from "./UI/Base/VariableUIElement";
|
||||
import {SearchAndGo} from "./UI/SearchAndGo";
|
||||
|
||||
let dryRun = false;
|
||||
|
||||
|
@ -182,6 +183,8 @@ const pendingChanges = new PendingChanges(
|
|||
new UserBadge(osmConnection.userDetails, pendingChanges, bm)
|
||||
.AttachTo('userbadge');
|
||||
|
||||
new SearchAndGo(bm).AttachTo("searchbox");
|
||||
|
||||
var welcomeMessage = () => {
|
||||
return new VariableUiElement(
|
||||
osmConnection.userDetails.map((userdetails) => {
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
<link href="index.css" rel="stylesheet"/>
|
||||
</head>
|
||||
<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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
17
test.ts
17
test.ts
|
@ -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");
|
||||
/*/
|
||||
|
||||
|
||||
|
||||
//*/
|
Loading…
Reference in a new issue