Changes based on user feedback

This commit is contained in:
Pieter Vander Vennet 2020-07-01 21:21:29 +02:00
parent 118a60c805
commit 1738fc4252
16 changed files with 342 additions and 64 deletions

View file

@ -26,7 +26,7 @@ export class Bos extends LayerDefinition {
]; ];
this.maxAllowedOverlapPercentage = 10; this.maxAllowedOverlapPercentage = 10;
this.minzoom = 14; this.minzoom = 13;
this.questions = [Quests.nameOf(this.name), Quests.accessNatureReserve, Quests.operator]; this.questions = [Quests.nameOf(this.name), Quests.accessNatureReserve, Quests.operator];
this.style = this.generateStyleFunction(); this.style = this.generateStyleFunction();
this.elementsToShow = [ this.elementsToShow = [

View file

@ -22,6 +22,7 @@ export class KnownSet {
public startLat: number; public startLat: number;
static allSets : any = {}; static allSets : any = {};
public welcomeTail: string;
constructor( constructor(
name: string, name: string,
@ -32,7 +33,8 @@ export class KnownSet {
startLon: number, startLon: number,
welcomeMessage: string, welcomeMessage: string,
gettingStartedPlzLogin: string, gettingStartedPlzLogin: string,
welcomeBackMessage: string welcomeBackMessage: string,
welcomeTail: string = ""
) { ) {
this.title = title; this.title = title;
this.startLon = startLon; this.startLon = startLon;
@ -43,6 +45,7 @@ export class KnownSet {
this.welcomeMessage = welcomeMessage; this.welcomeMessage = welcomeMessage;
this.gettingStartedPlzLogin = gettingStartedPlzLogin; this.gettingStartedPlzLogin = gettingStartedPlzLogin;
this.welcomeBackMessage = welcomeBackMessage; this.welcomeBackMessage = welcomeBackMessage;
this.welcomeTail = welcomeTail;
KnownSet.allSets[this.name] = this; KnownSet.allSets[this.name] = this;
} }
@ -50,35 +53,49 @@ export class KnownSet {
static groen = new KnownSet("groen", static groen = new KnownSet("groen",
"Buurtnatuur", "Buurtnatuur",
[new NatureReserves(), new Park(), new Bos()], [new NatureReserves(), new Park(), new Bos()],
14, 10,
51.2, 50.8435,
3.2, 4.3688,
" <img src=\"assets/groen.svg\" alt=\"logo partij groen\" id=\"logo\"/>\n" +
"\n" + "\n" +
" <h3>Buurtnatuur meten</h3>\n" + "<img src='assets/groen.svg' alt='logo-groen' class='logo'> <br />" +
"\n" + "<h3>Breng jouw buurtnatuur in kaart</h3>" +
"\n" + "<b>Natuur maakt gelukkig.</b> Aan de hand van deze website willen we de natuur dicht bij ons beter inventariseren. Met als doel meer mensen te laten genieten van toegankelijke natuur én te strijden voor meer natuur in onze buurten. \n" +
" Met deze tool willen we de natuur in Belgie beter inventariseren. <br/>\n" + "<ul>" +
" In welke natuurgebieden kan men terecht?<br/>\n" + "<li>In welke natuurgebieden kan jij terecht? Hoe toegankelijk zijn ze?</li>" +
" In welke bossen is het goed vertoeven?<br>\n" + "<li>In welke bossen kan een gezin in jouw gemeente opnieuw op adem komen?</li>" +
" <p>Natuur maakt immers gelukkig!</p>\n" + "<li>Op welke onbekende plekjes is het zalig spelen?</li>" +
"\n" + "</ul>" +
"<p>De data komt van <b>OpenStreetMap</b> en je antwoorden worden daar ook opgeslaan. " + "<p>Samen kleuren we heel Vlaanderen en Brussel groen.</p>" +
"Omdat iedereen aan deze data bijdraagt, kunnen we geen garantie op correctheid bieden en heeft deze data geen juridische waarde</p>\n" + "<p>Blijf op de hoogte van de resultaten van buurtnatuur.be: <a href=\"https://www.groen.be/buurtnatuur\" target='_blank'>meld je aan voor e-mailupdates</a>.</p> \n"
"<p>Je <b>privacy</b> is belangrijk. We tellen wel hoeveel personen de website bezoeken. Om je niet dubbel te tellen wordt er één cookie bijgehouden waar geen persoonlijke informatie in staat. " + ,
"Als je inlogt, komt er een tweede cookie bij met je inloggegevens.</p>\n",
" <p>Wil je meehelpen? <br/>\n" + "<b>Begin meteen door <a href=\"https://www.openstreetmap.org/user/new\" target=\"_blank\">een account te maken\n" +
" Begin dan met <a href=\"https://www.openstreetmap.org/user/new\" target=\"_blank\">een account\n" +
" te maken</a> of\n" + " te maken</a> of\n" +
" <span onclick=\"authOsm()\" class=\"activate-osm-authentication\">in te loggen</span>.</p>", " <span onclick=\"authOsm()\" class=\"activate-osm-authentication\">in te loggen</span>.</b>",
"Je bent aangemeld. Klik op een element om vragen te beantwoorden." "",
"<h4>Tips</h4>" +
"<ul>" +
"<li>Over groen ingekleurde gebieden weten we alles wat we willen weten.</li>" +
"<li>Bij rood ingekleurde gebieden ontbreekt nog heel wat info: klik een gebied aan en beantwoord de vragen.</li>" +
"<li>Je kan altijd een foto toevoegen</li>" +
"<li>Je kan ook zelf een gebied toevoegen door op de kaart te klikken</li>" +
"</ul>" +
"<small>" +
"<p>" +
"De oorspronkelijke data komt van <b>OpenStreetMap</b> en je antwoorden worden daar bewaard.<br/> Omdat iedereen vrij kan meewerken aan dit project, kunnen we niet garanderen dat er geen fouten opduiken." +
"</p>" +
"Je privacy is belangrijk. We tellen wel hoeveel gebruikers deze website bezoeken. We plaatsen een cookie waar geen persoonlijke informatie in bewaard wordt. " +
"Als je inlogt, komt er een tweede cookie bij met je inloggegevens." +
"</small>"
); );
static openToiletMap = new KnownSet( static openToiletMap = new KnownSet(
"toilets", "toilets",
"Open Toilet Map", "Open Toilet Map",
[new Toilets()], [new Toilets()],
14, 12,
51.2, 51.2,
3.2, 3.2,

View file

@ -171,7 +171,7 @@ export class FilteredLayer {
let marker; let marker;
if (style.icon === undefined) { if (style.icon === undefined) {
marker = L.circle(latLng, { marker = L.circle(latLng, {
radius: 50, radius: 25,
color: style.color color: style.color
}); });

View file

@ -1,16 +1,25 @@
import * as $ from "jquery" import * as $ from "jquery"
import {UIEventSource} from "../UI/UIEventSource"; import {UIEventSource} from "../UI/UIEventSource";
import {Basemap} from "./Basemap";
export class Geocoding { export class Geocoding {
private static readonly host = "https://nominatim.openstreetmap.org/search?"; private static readonly host = "https://nominatim.openstreetmap.org/search?";
static Search(query: string, currentLocation: UIEventSource<{ lat: number, lon: number }>, static Search(query: string,
handleResult: ((places: { display_name: string, lat: number, lon: number, boundingbox : number[] }[]) => void)) { basemap: Basemap,
handleResult: ((places: { display_name: string, lat: number, lon: number, boundingbox: number[] }[]) => void),
onFail: (() => void)) {
const b = basemap.map.getBounds();
console.log(b);
$.getJSON( $.getJSON(
Geocoding.host + "format=json&accept-language=nl&q=" + query, Geocoding.host + "format=json&limit=1&viewbox=" +
`${b.getEast()},${b.getNorth()},${b.getWest()},${b.getSouth()}`+
"&accept-language=nl&q=" + query,
function (data) { function (data) {
handleResult(data); handleResult(data);
}).fail(() => {
onFail();
}); });
} }

View file

@ -71,7 +71,8 @@ export class LayerUpdater {
if (this.IsInBounds()) { if (this.IsInBounds()) {
return; return;
} }
if (this._map.map.getZoom() < this._minzoom) { console.log("Zoom level: ",this._map.map.getZoom(), "Least needed zoom:", this._minzoom)
if (this._map.map.getZoom() < this._minzoom || this._map.Location.data.zoom < this._minzoom) {
console.log("Not running query: zoom not sufficient"); console.log("Not running query: zoom not sufficient");
return; return;
} }

View file

@ -144,6 +144,12 @@ export class OsmConnection {
} }
public SetPreference(k:string, v:string) { public SetPreference(k:string, v:string) {
if (this.preferences.data[k] === v) {
return;
}
console.log("Updating preference", k, " to ", v);
this.preferences.data[k] = v; this.preferences.data[k] = v;
this.preferences.ping(); this.preferences.ping();
this.auth.xhr({ this.auth.xhr({

View file

@ -44,6 +44,11 @@ export class Overpass {
console.log("Query failed") console.log("Query failed")
onFail(status); onFail(status);
} }
if(json.elements === [] && json.remarks.indexOf("runtime error") > 0){
console.log("Timeout or other runtime error");
return;
}
// @ts-ignore // @ts-ignore
const geojson = OsmToGeoJson.default(json); const geojson = OsmToGeoJson.default(json);
continuation(geojson); continuation(geojson);

43
UI/Base/CollapseButton.ts Normal file
View file

@ -0,0 +1,43 @@
import {UIElement} from "../UIElement";
import {UIEventSource} from "../UIEventSource";
export class CollapseButton extends UIElement {
public isCollapsed = new UIEventSource(false);
constructor(idToCollapse: string) {
super(undefined);
this.ListenTo(this.isCollapsed);
this.isCollapsed.addCallback((collapse) => {
const el = document.getElementById(idToCollapse);
if (el === undefined || el === null) {
console.log("Element not found")
return;
}
if (collapse) {
el.style.height = "3.5em";
el.style.width = "15em";
} else {
el.style.height = "auto";
el.style.width = "auto";
}
});
const self = this;
this.onClick(() => {
self.isCollapsed.setData(!self.isCollapsed.data);
})
}
protected InnerRender(): string {
const up = './assets/arrow-up.svg';
const down = './assets/arrow-down.svg';
let arrow = up;
if (this.isCollapsed.data) {
arrow = down;
}
return `<img class='collapse-button' src='${arrow}' alt='collapse'>`;
}
}

View file

@ -36,7 +36,7 @@ export class QuestionPicker extends UIElement {
if (highestQ === undefined) { if (highestQ === undefined) {
return ""; return "Er zijn geen vragen meer!";
} }
return "<div class='infobox-questions'>" + return "<div class='infobox-questions'>" +

View file

@ -1,16 +1,14 @@
import {UIElement} from "./UIElement"; import {UIElement} from "./UIElement";
import {TextField} from "./Base/TextField"; import {TextField} from "./Base/TextField";
import {VariableUiElement} from "./Base/VariableUIElement";
import {UIEventSource} from "./UIEventSource"; import {UIEventSource} from "./UIEventSource";
import {FixedUiElement} from "./Base/FixedUiElement"; import {FixedUiElement} from "./Base/FixedUiElement";
import {Geocoding} from "../Logic/Geocoding"; import {Geocoding} from "../Logic/Geocoding";
import {Basemap} from "../Logic/Basemap"; import {Basemap} from "../Logic/Basemap";
import {VerticalCombine} from "./Base/VerticalCombine";
export class SearchAndGo extends UIElement { export class SearchAndGo extends UIElement {
private _placeholder = new UIEventSource("Ga naar een locatie...") private _placeholder = new UIEventSource("Zoek naar een locatie...")
private _searchField = new TextField(this._placeholder); private _searchField = new TextField(this._placeholder);
private _foundEntries = new UIEventSource([]); private _foundEntries = new UIEventSource([]);
@ -39,7 +37,12 @@ export class SearchAndGo extends UIElement {
this._searchField.Clear(); this._searchField.Clear();
this._placeholder.setData("Bezig met zoeken..."); this._placeholder.setData("Bezig met zoeken...");
const self = this; const self = this;
Geocoding.Search(searchString, undefined, (result) => { Geocoding.Search(searchString, this._map, (result) => {
if (result.length == 0) {
this._placeholder.setData("Niets gevonden");
return;
}
const bb = result[0].boundingbox; const bb = result[0].boundingbox;
const bounds = [ const bounds = [
@ -47,7 +50,10 @@ export class SearchAndGo extends UIElement {
[bb[1], bb[3]] [bb[1], bb[3]]
] ]
self._map.map.fitBounds(bounds); self._map.map.fitBounds(bounds);
this._placeholder.setData("Ga naar locatie..."); this._placeholder.setData("Zoek naar een locatie...");
},
() => {
this._placeholder.setData("Niets gevonden: er ging iets mis");
}); });
} }

View file

@ -57,6 +57,7 @@ export abstract class UIElement {
element.onclick = () => { element.onclick = () => {
self._onClick(); self._onClick();
} }
element.style.pointerEvents = "all";
element.style.cursor = "pointer"; element.style.cursor = "pointer";
} }

76
assets/arrow-down.svg Normal file
View file

@ -0,0 +1,76 @@
<?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-down.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="4"
inkscape:cx="-22.237738"
inkscape:cy="36.323203"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1680"
inkscape:window-height="1013"
inkscape:window-x="0"
inkscape:window-y="0"
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></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.59588718;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 23.599389,276.87373 c 0,0 -7.53922,13.79953 -10.36091,13.84843 -2.82169,0.0489 -10.3860703,-13.84843 -10.3860703,-13.84843"
id="path821"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

76
assets/arrow-up.svg Normal file
View file

@ -0,0 +1,76 @@
<?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-up.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="4"
inkscape:cx="-22.237738"
inkscape:cy="36.323203"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1680"
inkscape:window-height="1013"
inkscape:window-x="0"
inkscape:window-y="0"
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.59588718;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.8524437,290.69991 c 0,0 7.5392203,-13.79953 10.3609103,-13.84843 2.82169,-0.0489 10.38607,13.84843 10.38607,13.84843"
id="path821"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -203,25 +203,46 @@ body {
pointer-events: none; pointer-events: none;
} }
#welcomeMessage {
display: inline-block;
max-width: 30em;
padding: 0;
padding-bottom: 1em;
}
#messagesboxmobilewrapper { #messagesboxmobilewrapper {
display: none; /*Only shown on small screens*/ display: none; /*Only shown on small screens*/
} }
#welcomeMessage {
max-width: 35em;
padding: 0;
padding-top: 1em;
padding-bottom: 1em;
}
#collapseButton {
position: absolute;
right: 0;
background-color: white;
margin: 1.5em;
border: 2px solid black;
border-radius: 2em;
padding: 0.5em;
display: inline-block;
width: 1em;
height: 1em;
}
#collapseButton img {
width: 1em;
height: 1em;
}
#messagesbox-wrapper {
}
#messagesbox { #messagesbox {
/*Only shown on big screens*/ /*Only shown on big screens*/
padding: 2em; padding: 2em;
padding-top: 1em; padding-top: 1em;
padding-bottom: 1em; padding-bottom: 1em;
z-index: 5000; z-index: 5000;
transition: all 500ms linear;
background-color: white; background-color: white;
border-radius: 2em; border-radius: 2em;
pointer-events: all; pointer-events: all;
@ -229,6 +250,10 @@ body {
@media only screen and (max-width: 600px) { @media only screen and (max-width: 600px) {
#messagesbox-wrapper {
display: none;
}
#messagesbox { #messagesbox {
display: none; display: none;
} }
@ -525,6 +550,10 @@ body {
/***************** Info box (box containing features and questions ******************/ /***************** Info box (box containing features and questions ******************/
.leaflet-popup-content {
width: 25vw !important;
}
.featureinfobox { .featureinfobox {
} }

View file

@ -30,7 +30,9 @@
<div id="searchbox"></div> <div id="searchbox"></div>
</div> </div>
<br/> <br/>
<div id="messagesbox"> <div id="messagesbox-wrapper">
<div id="collapseButton"></div>
<div id="messagesbox"></div>
</div> </div>
</div> </div>

View file

@ -20,6 +20,7 @@ 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"; import {SearchAndGo} from "./UI/SearchAndGo";
import {CollapseButton} from "./UI/Base/CollapseButton";
let dryRun = false; let dryRun = false;
@ -129,6 +130,8 @@ const addButtons: {
const flayers: FilteredLayer[] = [] const flayers: FilteredLayer[] = []
let minZoom = 0;
for (const layer of questSetToRender.layers) { for (const layer of questSetToRender.layers) {
const generateInfo = (tagsES) => { const generateInfo = (tagsES) => {
@ -143,6 +146,8 @@ for (const layer of questSetToRender.layers) {
) )
}; };
minZoom = Math.max(minZoom, layer.minzoom);
const flayer = layer.asLayer(bm, allElements, changes, osmConnection.userDetails, selectedElement, const flayer = layer.asLayer(bm, allElements, changes, osmConnection.userDetails, selectedElement,
generateInfo); generateInfo);
@ -156,7 +161,7 @@ for (const layer of questSetToRender.layers) {
flayers.push(flayer); flayers.push(flayer);
} }
const layerUpdater = new LayerUpdater(bm, questSetToRender.startzoom, flayers); const layerUpdater = new LayerUpdater(bm, minZoom, flayers);
// ------------------ Setup various UI elements ------------ // ------------------ Setup various UI elements ------------
@ -207,6 +212,8 @@ new UserBadge(osmConnection.userDetails, pendingChanges, bm)
new SearchAndGo(bm).AttachTo("searchbox"); new SearchAndGo(bm).AttachTo("searchbox");
new CollapseButton("messagesbox")
.AttachTo("collapseButton");
var welcomeMessage = () => { var welcomeMessage = () => {
return new VariableUiElement( return new VariableUiElement(
osmConnection.userDetails.map((userdetails) => { osmConnection.userDetails.map((userdetails) => {
@ -215,7 +222,7 @@ var welcomeMessage = () => {
login = questSetToRender.welcomeBackMessage; login = questSetToRender.welcomeBackMessage;
} }
return "<div id='welcomeMessage'>" + return "<div id='welcomeMessage'>" +
questSetToRender.welcomeMessage + login + questSetToRender.welcomeMessage + login + questSetToRender.welcomeTail+
"</div>"; "</div>";
}), }),
function () { function () {
@ -229,7 +236,7 @@ welcomeMessage().AttachTo("messagesbox");
var messageBox = new MessageBoxHandler(leftMessage, () => {selectedElement.setData(undefined)}); var messageBox = new MessageBoxHandler(leftMessage, () => {selectedElement.setData(undefined)});
new CenterMessageBox( new CenterMessageBox(
questSetToRender.startzoom, minZoom,
centerMessage, centerMessage,
osmConnection, osmConnection,
locationControl, locationControl,