Add bigger zoom-in and zoom-out button, move attribution to button on small screens

This commit is contained in:
pietervdvn 2021-02-21 03:38:12 +01:00
parent 2572e99b95
commit 604d7863fe
13 changed files with 142 additions and 66 deletions

File diff suppressed because one or more lines are too long

View file

@ -34,6 +34,9 @@ import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline";
import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler"; import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler";
import ScrollableFullScreen from "./UI/Base/ScrollableFullScreen"; import ScrollableFullScreen from "./UI/Base/ScrollableFullScreen";
import Translations from "./UI/i18n/Translations"; import Translations from "./UI/i18n/Translations";
import MapControlButton from "./UI/MapControlButton";
import {Map} from "leaflet";
import Combine from "./UI/Base/Combine";
export class InitUiElements { export class InitUiElements {
@ -122,8 +125,11 @@ export class InitUiElements {
if ((window != window.top && !State.state.featureSwitchWelcomeMessage.data) || State.state.featureSwitchIframe.data) { if ((window != window.top && !State.state.featureSwitchWelcomeMessage.data) || State.state.featureSwitchIframe.data) {
const currentLocation = State.state.locationControl; const currentLocation = State.state.locationControl;
const url = `${window.location.origin}${window.location.pathname}?z=${currentLocation.data.zoom}&lat=${currentLocation.data.lat}&lon=${currentLocation.data.lon}`; const url = `${window.location.origin}${window.location.pathname}?z=${currentLocation.data.zoom ?? 0}&lat=${currentLocation.data.lat ?? 0}&lon=${currentLocation.data.lon ?? 0}`;
new Link(Svg.pop_out_ui().SetClass("iframe-escape"), url, true) new MapControlButton(
new Link(Svg.pop_out_img, url, true)
.SetClass("block w-full h-full p-1.5")
)
.AttachTo("messagesbox"); .AttachTo("messagesbox");
} }
@ -142,14 +148,31 @@ export class InitUiElements {
marker.addTo(State.state.leafletMap.data) marker.addTo(State.state.leafletMap.data)
}); });
new FeatureSwitched( const geolocationButton = new FeatureSwitched(
new MapControlButton(
new GeoLocationHandler( new GeoLocationHandler(
State.state.currentGPSLocation, State.state.currentGPSLocation,
State.state.leafletMap State.state.leafletMap
) )),
.SetStyle(`position:relative;display:block;border: solid 2px #0005;cursor: pointer; z-index: 999; /*Just below leaflets zoom*/background-color: white;border-radius: 5px;width: 43px;height: 43px;`) State.state.featureSwitchGeolocation);
, State.state.featureSwitchGeolocation)
.AttachTo("geolocate-button"); const plus = new MapControlButton(
Svg.plus_ui()
).onClick(() => {
State.state.locationControl.data.zoom++;
State.state.locationControl.ping();
})
const min = new MapControlButton(
Svg.min_ui()
).onClick(() => {
State.state.locationControl.data.zoom--;
State.state.locationControl.ping();
})
new Combine([plus, min, geolocationButton].map(el => el.SetClass("m-1")))
.SetClass("flex flex-col")
.AttachTo("bottom-right");
if (layoutToUse.id === personal.id) { if (layoutToUse.id === personal.id) {
updateFavs(); updateFavs();
@ -159,7 +182,7 @@ export class InitUiElements {
if (layoutToUse.id === personal.id) { if (layoutToUse.id === personal.id) {
State.state.favouriteLayers.addCallback(updateFavs); State.state.favouriteLayers.addCallback(updateFavs);
State.state.installedThemes.addCallback(updateFavs); State.state.installedThemes.addCallback(updateFavs);
}else{ } else {
State.state.locationControl.ping(); State.state.locationControl.ping();
} }
@ -247,15 +270,39 @@ export class InitUiElements {
.SetClass("block p-1 rounded-full"); .SetClass("block p-1 rounded-full");
const checkbox = new CheckBox( const checkbox = new CheckBox(
layerControlPanel, layerControlPanel,
Svg.layers_svg().SetClass("layer-selection-toggle"), new MapControlButton(Svg.layers_svg()),
State.state.layerControlIsOpened State.state.layerControlIsOpened
).AttachTo("layer-selection"); )
const copyrightState = new UIEventSource<boolean>(false);
const copyrightNotice =
new ScrollableFullScreen(
Translations.t.general.attribution.attributionTitle,
new Combine([
Translations.t.general.attribution.attributionContent,
"<br/>",
new Attribution(undefined, undefined, State.state.layoutToUse, undefined)
]),
() => {
copyrightState.setData(false)
}
)
;
const copyrightButton = new CheckBox(
copyrightNotice,
new MapControlButton(Svg.osm_copyright_svg()),
copyrightState
).SetClass("p-0.5 md:hidden")
new Combine([copyrightButton, checkbox])
.AttachTo("layer-selection");
State.state.locationControl State.state.locationControl
.addCallback(() => { .addCallback(() => {
// Close the layer selection when the map is moved // Close the layer selection when the map is moved
checkbox.isEnabled.setData(false); checkbox.isEnabled.setData(false);
copyrightButton.isEnabled.setData(false);
}); });
State.state.selectedElement.addCallbackAndRun(feature => { State.state.selectedElement.addCallbackAndRun(feature => {

View file

@ -20,6 +20,7 @@ export default class GeoLocationHandler extends UIElement {
this._currentGPSLocation = currentGPSLocation; this._currentGPSLocation = currentGPSLocation;
this._leafletMap = leafletMap; this._leafletMap = leafletMap;
this._hasLocation = currentGPSLocation.map((location) => location !== undefined); this._hasLocation = currentGPSLocation.map((location) => location !== undefined);
this.dumbMode = false;
const self = this; const self = this;
import("../../vendor/Leaflet.AccuratePosition.js").then(() => { import("../../vendor/Leaflet.AccuratePosition.js").then(() => {
self.init(); self.init();
@ -117,6 +118,7 @@ export default class GeoLocationHandler extends UIElement {
private StartGeolocating(zoomlevel = 19) { private StartGeolocating(zoomlevel = 19) {
const self = this; const self = this;
console.log("Starting geolocation")
const map: any = this._leafletMap.data; const map: any = this._leafletMap.data;
if (self._permission.data === "denied") { if (self._permission.data === "denied") {
return ""; return "";

View file

@ -18,7 +18,9 @@ export default class SelectedFeatureHandler {
this._featureSource = featureSource; this._featureSource = featureSource;
const self = this; const self = this;
hash.addCallback(h => { hash.addCallback(h => {
console.log("Hash is now ", h)
if (h === undefined || h === "") { if (h === undefined || h === "") {
console.log("Deselecting feature...")
selectedFeature.setData(undefined); selectedFeature.setData(undefined);
}else{ }else{
self.selectFeature(); self.selectFeature();

View file

@ -2,7 +2,7 @@ import { Utils } from "../Utils";
export default class Constants { export default class Constants {
public static vNumber = "0.5.0b"; public static vNumber = "0.5.1";
// The user journey states thresholds when a new feature gets unlocked // The user journey states thresholds when a new feature gets unlocked
public static userJourney = { public static userJourney = {

17
Svg.ts

File diff suppressed because one or more lines are too long

View file

@ -32,13 +32,13 @@ export default class Attribution extends UIElement {
} }
InnerRender(): string { InnerRender(): string {
const location : Loc = this._location.data; const location : Loc = this._location?.data;
const userDetails = this._userDetails.data; const userDetails = this._userDetails?.data;
const mapComplete = new Link(`Mapcomplete ${Constants.vNumber}`, 'https://github.com/pietervdvn/MapComplete', true); const mapComplete = new Link(`Mapcomplete ${Constants.vNumber}`, 'https://github.com/pietervdvn/MapComplete', true);
const reportBug = new Link(Svg.bug_img, "https://github.com/pietervdvn/MapComplete/issues", true); const reportBug = new Link(Svg.bug_img, "https://github.com/pietervdvn/MapComplete/issues", true);
const layoutId = this._layoutToUse.data.id; const layoutId = this._layoutToUse?.data?.id;
const osmChaLink = `https://osmcha.org/?filters=%7B%22comment%22%3A%5B%7B%22label%22%3A%22%23${layoutId}%22%2C%22value%22%3A%22%23${layoutId}%22%7D%5D%2C%22date__gte%22%3A%5B%7B%22label%22%3A%222020-07-05%22%2C%22value%22%3A%222020-07-05%22%7D%5D%2C%22editor%22%3A%5B%7B%22label%22%3A%22MapComplete%22%2C%22value%22%3A%22MapComplete%22%7D%5D%7D` const osmChaLink = `https://osmcha.org/?filters=%7B%22comment%22%3A%5B%7B%22label%22%3A%22%23${layoutId}%22%2C%22value%22%3A%22%23${layoutId}%22%7D%5D%2C%22date__gte%22%3A%5B%7B%22label%22%3A%222020-07-05%22%2C%22value%22%3A%222020-07-05%22%7D%5D%2C%22editor%22%3A%5B%7B%22label%22%3A%22MapComplete%22%2C%22value%22%3A%22MapComplete%22%7D%5D%7D`
const stats = new Link(Svg.statistics_img, osmChaLink, true) const stats = new Link(Svg.statistics_img, osmChaLink, true)
let editHere: (UIElement | string) = ""; let editHere: (UIElement | string) = "";
@ -48,7 +48,7 @@ export default class Attribution extends UIElement {
} }
let editWithJosm: (UIElement | string) = "" let editWithJosm: (UIElement | string) = ""
if (location !== undefined && if (location !== undefined &&
this._leafletMap.data !== undefined && this._leafletMap?.data !== undefined &&
userDetails.csCount >= Constants.userJourney.tagsVisibleAndWikiLinked) { userDetails.csCount >= Constants.userJourney.tagsVisibleAndWikiLinked) {
const bounds : any= this._leafletMap.data.getBounds(); const bounds : any= this._leafletMap.data.getBounds();
const top = bounds.getNorth(); const top = bounds.getNorth();
@ -59,7 +59,7 @@ export default class Attribution extends UIElement {
const josmLink = `http://127.0.0.1:8111/load_and_zoom?left=${left}&right=${right}&top=${top}&bottom=${bottom}` const josmLink = `http://127.0.0.1:8111/load_and_zoom?left=${left}&right=${right}&top=${top}&bottom=${bottom}`
editWithJosm = new Link(Svg.josm_logo_img, josmLink, true); editWithJosm = new Link(Svg.josm_logo_img, josmLink, true);
} }
return new Combine([mapComplete, reportBug, " | ", stats, " | ", editHere, editWithJosm]).Render(); return new Combine([mapComplete, reportBug, stats, editHere, editWithJosm]).Render();
} }

View file

@ -36,7 +36,6 @@ export class Basemap {
this.map.attributionControl.setPrefix( this.map.attributionControl.setPrefix(
extraAttribution.Render() + " | <a href='https://osm.org'>OpenStreetMap</a>"); extraAttribution.Render() + " | <a href='https://osm.org'>OpenStreetMap</a>");
this.map.zoomControl.setPosition("bottomright");
const self = this; const self = this;
let previousLayer = currentLayer.data; let previousLayer = currentLayer.data;
@ -59,6 +58,13 @@ export class Basemap {
location.ping(); location.ping();
}); });
location.map(loc => loc.zoom)
.addCallback(zoom => {
if (Math.abs(self.map.getZoom() - zoom) > 0.1) {
self.map.setZoom(zoom, {});
}
})
this.map.on("click", function (e) { this.map.on("click", function (e) {
// @ts-ignore // @ts-ignore
lastClickLocation.setData({lat: e.latlng.lat, lon: e.latlng.lng}) lastClickLocation.setData({lat: e.latlng.lat, lon: e.latlng.lng})

20
UI/MapControlButton.ts Normal file
View file

@ -0,0 +1,20 @@
import {UIElement} from "./UIElement";
/**
* A button floating above the map, in a uniform style
*/
export default class MapControlButton extends UIElement {
private _contents: UIElement;
constructor(contents: UIElement) {
super();
this._contents = contents;
this.SetClass("relative block rounded-full w-10 h-10 p-1 pointer-events-auto z-above-map subtle-background")
this.SetStyle("box-shadow: 0 0 10px var(--shadow-color);");
}
InnerRender(): string {
return this._contents.Render();
}
}

View file

@ -513,6 +513,16 @@
"gl": "<h3>Un mapa aberto</h3><p></p>Non sería xenial se houbera un só mapa, que todos puideran empregar e editar de xeito libre?Un só lugar para almacenar toda a información xeográfica? Entón, todos eses sitios web con mapas diferentes, pequenos e incompatíbeis (que sempre están desactualizados) xa non serían necesarios.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> é ese mapa. Os datos do mapa pódense empregar de balde (con <a href='https://osm.org/copyright' target='_blank'> atribución e publicación de modificacións neses datos</a>).Ademais diso, todos poden engadir de xeito ceibe novos datos e corrixir erros. Este sitio web tamén emprega o OpenStreetMap. Todos os datos proveñen de alí, e as túas respostas e correccións tamén serán engadidas alí.</p><p>Moitas persoas e aplicacións xa empregan o OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, pero tamén os mapas do Facebook, Instagram, Apple e Bing son (en parte) impulsados polo OpenStreetMap.Se mudas algo aquí, tamén será reflexado nesas aplicacións, na súa seguinte actualización!</p>", "gl": "<h3>Un mapa aberto</h3><p></p>Non sería xenial se houbera un só mapa, que todos puideran empregar e editar de xeito libre?Un só lugar para almacenar toda a información xeográfica? Entón, todos eses sitios web con mapas diferentes, pequenos e incompatíbeis (que sempre están desactualizados) xa non serían necesarios.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> é ese mapa. Os datos do mapa pódense empregar de balde (con <a href='https://osm.org/copyright' target='_blank'> atribución e publicación de modificacións neses datos</a>).Ademais diso, todos poden engadir de xeito ceibe novos datos e corrixir erros. Este sitio web tamén emprega o OpenStreetMap. Todos os datos proveñen de alí, e as túas respostas e correccións tamén serán engadidas alí.</p><p>Moitas persoas e aplicacións xa empregan o OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, pero tamén os mapas do Facebook, Instagram, Apple e Bing son (en parte) impulsados polo OpenStreetMap.Se mudas algo aquí, tamén será reflexado nesas aplicacións, na súa seguinte actualización!</p>",
"de": "<h3>Eine offene Karte</h3><p>Wäre es nicht toll, wenn es eine offene Karte gäbe, die von jedem angepasst und benutzt werden könnte? Eine Karte, zu der jeder seine Interessen hinzufügen kann? Dann bräuchte man all diese Websites mit unterschiedlichen, kleinen und inkompatiblen Karten (die immer veraltet sind) nicht mehr.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> ist diese offene Karte. Die Kartendaten können kostenlos verwendet werden (mit <a href='https://osm.org/copyright' target='_blank'>Attribution und Veröffentlichung von Änderungen an diesen Daten</a>). Darüber hinaus können Sie die Karte kostenlos ändern und Fehler beheben, wenn Sie ein Konto erstellen. Diese Website basiert ebenfalls auf OpenStreetMap. Wenn Sie eine Frage hier beantworten, geht die Antwort auch dorthin.</p>Viele Menschen und Anwendungen nutzen OpenStreetMap bereits: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, verschiedene spezialisierte Routenplaner, die Hintergrundkarten auf Facebook, Instagram,...<br/>Sogar Apple Maps und Bing Maps verwenden OpenStreetMap in ihren Karten!</p></p><p>Wenn Sie hier einen Punkt hinzufügen oder eine Frage beantworten, wird er nach einer Weile in all diesen Anwendungen sichtbar sein.</p>" "de": "<h3>Eine offene Karte</h3><p>Wäre es nicht toll, wenn es eine offene Karte gäbe, die von jedem angepasst und benutzt werden könnte? Eine Karte, zu der jeder seine Interessen hinzufügen kann? Dann bräuchte man all diese Websites mit unterschiedlichen, kleinen und inkompatiblen Karten (die immer veraltet sind) nicht mehr.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> ist diese offene Karte. Die Kartendaten können kostenlos verwendet werden (mit <a href='https://osm.org/copyright' target='_blank'>Attribution und Veröffentlichung von Änderungen an diesen Daten</a>). Darüber hinaus können Sie die Karte kostenlos ändern und Fehler beheben, wenn Sie ein Konto erstellen. Diese Website basiert ebenfalls auf OpenStreetMap. Wenn Sie eine Frage hier beantworten, geht die Antwort auch dorthin.</p>Viele Menschen und Anwendungen nutzen OpenStreetMap bereits: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, verschiedene spezialisierte Routenplaner, die Hintergrundkarten auf Facebook, Instagram,...<br/>Sogar Apple Maps und Bing Maps verwenden OpenStreetMap in ihren Karten!</p></p><p>Wenn Sie hier einen Punkt hinzufügen oder eine Frage beantworten, wird er nach einer Weile in all diesen Anwendungen sichtbar sein.</p>"
}, },
"attribution": {
"attributionTitle": {
"en": "Attribution notice",
"nl": "Met dank aan"
},
"attributionContent": {
"en": "<p>All data is provided by <a href='https://osm.org' target='_blank'>OpenStreetMap</a>, freely reusable under <a href='https://osm.org/copyright' target='_blank'>the Open DataBase License</a>.</p><p>Some images are provided by Wikimedia</p>"
}
},
"sharescreen": { "sharescreen": {
"intro": { "intro": {
"en": "<h3>Share this map</h3> Share this map by copying the link below and sending it to friends and family:", "en": "<h3>Share this map</h3> Share this map by copying the link below and sending it to friends and family:",

View file

@ -51,6 +51,13 @@ Contains tweaks for small screens
} }
} }
@media only screen and (max-width: 768px) {
.leaflet-control-attribution{
display: none;
}
}
@media only screen and (max-width: 600px) { @media only screen and (max-width: 600px) {
/* Portrait */ /* Portrait */
#userbadge-and-search { #userbadge-and-search {

View file

@ -122,6 +122,9 @@ a {
color: var(--foreground-color); color: var(--foreground-color);
} }
.subtle-background {
background: var(--subtle-detail-color);
}
.slick-prev:before, .slick-next:before { .slick-prev:before, .slick-next:before {
/*Slideshow workaround*/ /*Slideshow workaround*/
color:black !important; color:black !important;
@ -163,34 +166,6 @@ a {
box-shadow: 0 3px 14px var(--shadow-color) !important; box-shadow: 0 3px 14px var(--shadow-color) !important;
} }
#geolocate-button {
position: absolute;
bottom: 25px;
right: 50px;
}
#geolocate-button img {
width: 31px;
height: 31px;
margin: 6px;
}
#geolocate-button > .uielement {
display: block;
}
#layer-selection {
z-index: 9000;
background-color: var(--background-color);
color: var(--foreground-color);
cursor: pointer;
box-shadow: 0 0 10px var(--shadow-color);
}
.single-layer-selection-toggle { .single-layer-selection-toggle {
position: relative; position: relative;
width: 2em; width: 2em;
@ -225,18 +200,6 @@ a {
max-width: 3.5em !important; max-width: 3.5em !important;
} }
.layer-selection-toggle {
display: flex;
flex-direction: column-reverse;
background: var(--subtle-detail-color);
}
.layer-selection-toggle svg {
display: block;
width: 2em;
height: 2em;
padding: 0.75em;
}
/**************** GENERIC ****************/ /**************** GENERIC ****************/

View file

@ -55,13 +55,14 @@
<div id="messagesbox" class="rounded-3xl overflow-hidden ml-3"></div> <div id="messagesbox" class="rounded-3xl overflow-hidden ml-3"></div>
</div> </div>
<div id="layer-selection" class="absolute bottom-3 left-3 rounded-3xl overflow-hidden clutter"></div> <div id="layer-selection" class="absolute bottom-3 left-3 rounded-3xl clutter z-above-map"></div>
<div id="bottom-right" class="absolute bottom-3 right-2 rounded-3xl clutter z-above-map"></div>
<div id="centermessage" class="clutter absolute rounded-3xl h-24 left-24 right-24 top-56 bg-white p-3 pt-5 sm:pt-8 text-xl font-bold text-center"> <div id="centermessage" class="clutter absolute rounded-3xl h-24 left-24 right-24 top-56 bg-white p-3 pt-5 sm:pt-8 text-xl font-bold text-center">
Loading MapComplete, hang on... Loading MapComplete, hang on...
</div> </div>
<div id="geolocate-button" class="clutter"></div>
<div id="leafletDiv"></div> <div id="leafletDiv"></div>
<script src="./index.ts"></script> <script src="./index.ts"></script>