forked from MapComplete/MapComplete
Add smoothness, add highlighting of a way
This commit is contained in:
parent
8af25a9cdf
commit
afaaaaadb1
12 changed files with 146 additions and 12 deletions
|
@ -10,6 +10,7 @@ import {MetaMap} from "./Layouts/MetaMap";
|
||||||
import {StreetWidth} from "./Layouts/StreetWidth";
|
import {StreetWidth} from "./Layouts/StreetWidth";
|
||||||
import {Natuurpunt} from "./Layouts/Natuurpunt";
|
import {Natuurpunt} from "./Layouts/Natuurpunt";
|
||||||
import {ClimbingTrees} from "./Layouts/ClimbingTrees";
|
import {ClimbingTrees} from "./Layouts/ClimbingTrees";
|
||||||
|
import {Smoothness} from "./Layouts/Smoothness";
|
||||||
|
|
||||||
export class AllKnownLayouts {
|
export class AllKnownLayouts {
|
||||||
public static allSets = AllKnownLayouts.AllLayouts();
|
public static allSets = AllKnownLayouts.AllLayouts();
|
||||||
|
@ -25,9 +26,9 @@ export class AllKnownLayouts {
|
||||||
new StreetWidth(),
|
new StreetWidth(),
|
||||||
new Natuurpunt(),
|
new Natuurpunt(),
|
||||||
new ClimbingTrees(),
|
new ClimbingTrees(),
|
||||||
new Artworks()
|
new Artworks(),
|
||||||
|
new Smoothness()
|
||||||
/*new Toilets(),
|
/*new Toilets(),
|
||||||
new Statues(),
|
|
||||||
*/
|
*/
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ export class LayerDefinition {
|
||||||
*/
|
*/
|
||||||
style: (tags: any) => {
|
style: (tags: any) => {
|
||||||
color: string,
|
color: string,
|
||||||
|
weight?: number,
|
||||||
icon: {
|
icon: {
|
||||||
iconUrl: string,
|
iconUrl: string,
|
||||||
iconSize: number[],
|
iconSize: number[],
|
||||||
|
|
|
@ -171,7 +171,7 @@ export class Widths extends LayerDefinition {
|
||||||
return {
|
return {
|
||||||
icon: null,
|
icon: null,
|
||||||
color: c,
|
color: c,
|
||||||
weight: 7,
|
weight: 10,
|
||||||
dashArray: dashArray
|
dashArray: dashArray
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,12 @@ export class Layout {
|
||||||
|
|
||||||
public hideFromOverview : boolean = false;
|
public hideFromOverview : boolean = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The BBOX of the currently visible map are widened by this factor, in order to make some panning possible.
|
||||||
|
* This number influences this
|
||||||
|
*/
|
||||||
|
public widenFactor : number = 0.07;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param name: The name used in the query string. If in the query "quests=<name>" is defined, it will select this layout
|
* @param name: The name used in the query string. If in the query "quests=<name>" is defined, it will select this layout
|
||||||
|
@ -128,7 +134,7 @@ export class WelcomeMessage extends UIElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InnerUpdate(htmlElement: HTMLElement) {
|
protected InnerUpdate(htmlElement: HTMLElement) {
|
||||||
this.osmConnection.registerActivateOsmAUthenticationClass()
|
this.osmConnection?.registerActivateOsmAUthenticationClass()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
81
Customizations/Layouts/Smoothness.ts
Normal file
81
Customizations/Layouts/Smoothness.ts
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import {Layout} from "../Layout";
|
||||||
|
import {LayerDefinition} from "../LayerDefinition";
|
||||||
|
import {Or, Tag} from "../../Logic/TagsFilter";
|
||||||
|
import {TagRenderingOptions} from "../TagRendering";
|
||||||
|
|
||||||
|
|
||||||
|
export class SmoothnessLayer extends LayerDefinition {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.name = "smoothness";
|
||||||
|
this.minzoom = 17;
|
||||||
|
this.overpassFilter = new Or([
|
||||||
|
new Tag("highway", "residential"),
|
||||||
|
new Tag("highway", "cycleway"),
|
||||||
|
new Tag("highway", "footway"),
|
||||||
|
new Tag("highway", "path"),
|
||||||
|
new Tag("highway", "tertiary")
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.elementsToShow = [
|
||||||
|
new TagRenderingOptions({
|
||||||
|
question: "How smooth is this road to rollerskate on",
|
||||||
|
mappings: [
|
||||||
|
{k: new Tag("smoothness","bad"), txt: "It's horrible"},
|
||||||
|
{k: new Tag("smoothness","intermediate"), txt: "It is passable by rollerscate, but only if you have to"},
|
||||||
|
{k: new Tag("smoothness","good"), txt: "Good, but it has some friction or holes"},
|
||||||
|
{k: new Tag("smoothness","very_good"), txt: "Quite good and enjoyable"},
|
||||||
|
{k: new Tag("smoothness","excellent"), txt: "Excellent - this is where you'd want to drive 24/7"},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
|
this.style = (properties) => {
|
||||||
|
let color = "#000000";
|
||||||
|
if(new Tag("smoothness","bad").matchesProperties(properties)){
|
||||||
|
color = "#ff0000";
|
||||||
|
}
|
||||||
|
if(new Tag("smoothness","intermediate").matchesProperties(properties)){
|
||||||
|
color = "#ffaa00";
|
||||||
|
}
|
||||||
|
if(new Tag("smoothness","good").matchesProperties(properties)){
|
||||||
|
color = "#ccff00";
|
||||||
|
}
|
||||||
|
if(new Tag("smoothness","very_good").matchesProperties(properties)){
|
||||||
|
color = "#00aa00";
|
||||||
|
}
|
||||||
|
if(new Tag("smoothness","excellent").matchesProperties(properties)){
|
||||||
|
color = "#00ff00";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: color,
|
||||||
|
icon: undefined,
|
||||||
|
weight: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Smoothness extends Layout {
|
||||||
|
constructor() {
|
||||||
|
super(
|
||||||
|
"smoothness",
|
||||||
|
["en" ],
|
||||||
|
"Smoothness while rollerskating",
|
||||||
|
[new SmoothnessLayer()],
|
||||||
|
17,
|
||||||
|
51.2,
|
||||||
|
3.2,
|
||||||
|
"Give smoothness feedback for rollerskating"
|
||||||
|
);
|
||||||
|
this.widenFactor = 0.005
|
||||||
|
this.hideFromOverview = true;
|
||||||
|
this.enableAdd = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,7 @@ export class FilteredLayer {
|
||||||
private readonly _map: Basemap;
|
private readonly _map: Basemap;
|
||||||
private readonly _maxAllowedOverlap: number;
|
private readonly _maxAllowedOverlap: number;
|
||||||
|
|
||||||
private readonly _style: (properties) => { color: string, icon: { iconUrl: string, iconSize? : number[], popupAnchor?: number[], iconAnchor?:number[] } };
|
private readonly _style: (properties) => { color: string, weight?: number, icon: { iconUrl: string, iconSize? : number[], popupAnchor?: number[], iconAnchor?:number[] } };
|
||||||
|
|
||||||
private readonly _storage: ElementStorage;
|
private readonly _storage: ElementStorage;
|
||||||
|
|
||||||
|
@ -239,19 +239,37 @@ export class FilteredLayer {
|
||||||
},
|
},
|
||||||
|
|
||||||
onEachFeature: function (feature, layer) {
|
onEachFeature: function (feature, layer) {
|
||||||
let eventSource = self._storage.addOrGetElement(feature);
|
|
||||||
eventSource.addCallback(function () {
|
feature.updateStyle = () => {
|
||||||
if (layer.setIcon) {
|
if (layer.setIcon) {
|
||||||
layer.setIcon(L.icon(self._style(feature.properties).icon))
|
layer.setIcon(L.icon(self._style(feature.properties).icon))
|
||||||
} else {
|
} else {
|
||||||
self._geolayer.setStyle(function (feature) {
|
self._geolayer.setStyle(function (feature) {
|
||||||
return self._style(feature.properties);
|
const style = self._style(feature.properties);
|
||||||
|
if (self._selectedElement.data?.feature === feature) {
|
||||||
|
if (style.weight !== undefined) {
|
||||||
|
style.weight = style.weight * 2;
|
||||||
|
}else{
|
||||||
|
style.weight = 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return style;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
let eventSource = self._storage.addOrGetElement(feature);
|
||||||
|
|
||||||
|
|
||||||
|
eventSource.addCallback(feature.updateStyle);
|
||||||
|
|
||||||
layer.on("click", function (e) {
|
layer.on("click", function (e) {
|
||||||
|
const previousFeature = self._selectedElement.data?.feature;
|
||||||
self._selectedElement.setData({feature: feature});
|
self._selectedElement.setData({feature: feature});
|
||||||
|
feature.updateStyle();
|
||||||
|
previousFeature?.updateStyle();
|
||||||
|
|
||||||
|
|
||||||
if (feature.geometry.type === "Point") {
|
if (feature.geometry.type === "Point") {
|
||||||
return; // Points bind there own popups
|
return; // Points bind there own popups
|
||||||
}
|
}
|
||||||
|
@ -267,7 +285,6 @@ export class FilteredLayer {
|
||||||
uiElement.Update();
|
uiElement.Update();
|
||||||
uiElement.Activate();
|
uiElement.Activate();
|
||||||
L.DomEvent.stop(e); // Marks the event as consumed
|
L.DomEvent.stop(e); // Marks the event as consumed
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {Basemap} from "./Leaflet/Basemap";
|
||||||
export class LayerUpdater {
|
export class LayerUpdater {
|
||||||
private _map: Basemap;
|
private _map: Basemap;
|
||||||
private _layers: FilteredLayer[];
|
private _layers: FilteredLayer[];
|
||||||
|
private widenFactor: number;
|
||||||
|
|
||||||
public readonly runningQuery: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
public readonly runningQuery: UIEventSource<boolean> = new UIEventSource<boolean>(false);
|
||||||
public readonly retries: UIEventSource<number> = new UIEventSource<number>(0);
|
public readonly retries: UIEventSource<number> = new UIEventSource<number>(0);
|
||||||
|
@ -27,7 +28,9 @@ export class LayerUpdater {
|
||||||
*/
|
*/
|
||||||
constructor(map: Basemap,
|
constructor(map: Basemap,
|
||||||
minzoom: number,
|
minzoom: number,
|
||||||
|
widenFactor: number,
|
||||||
layers: FilteredLayer[]) {
|
layers: FilteredLayer[]) {
|
||||||
|
this.widenFactor = widenFactor;
|
||||||
this._map = map;
|
this._map = map;
|
||||||
this._layers = layers;
|
this._layers = layers;
|
||||||
this._minzoom = minzoom;
|
this._minzoom = minzoom;
|
||||||
|
@ -97,7 +100,7 @@ export class LayerUpdater {
|
||||||
|
|
||||||
const bounds = this._map.map.getBounds();
|
const bounds = this._map.map.getBounds();
|
||||||
|
|
||||||
const diff =0.07;
|
const diff = this.widenFactor;
|
||||||
|
|
||||||
const n = bounds.getNorth() + diff;
|
const n = bounds.getNorth() + diff;
|
||||||
const e = bounds.getEast() + diff;
|
const e = bounds.getEast() + diff;
|
||||||
|
|
|
@ -91,6 +91,8 @@ export class OsmConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.UpdatePreferences();
|
self.UpdatePreferences();
|
||||||
|
self.CheckForMessagesContinuously();
|
||||||
|
|
||||||
// details is an XML DOM of user details
|
// details is an XML DOM of user details
|
||||||
let userInfo = details.getElementsByTagName("user")[0];
|
let userInfo = details.getElementsByTagName("user")[0];
|
||||||
|
|
||||||
|
@ -120,9 +122,21 @@ export class OsmConnection {
|
||||||
data.unreadMessages = parseInt(messages.getAttribute("unread"));
|
data.unreadMessages = parseInt(messages.getAttribute("unread"));
|
||||||
data.totalMessages = parseInt(messages.getAttribute("count"));
|
data.totalMessages = parseInt(messages.getAttribute("count"));
|
||||||
self.userDetails.ping();
|
self.userDetails.ping();
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private CheckForMessagesContinuously() {
|
||||||
|
const self = this;
|
||||||
|
window.setTimeout(() => {
|
||||||
|
if (self.userDetails.data.loggedIn) {
|
||||||
|
console.log("Checking for messages")
|
||||||
|
this.AttemptLogin();
|
||||||
|
}
|
||||||
|
}, 5 * 60 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All elements with class 'activate-osm-authentication' are loaded and get an 'onclick' to authenticate
|
* All elements with class 'activate-osm-authentication' are loaded and get an 'onclick' to authenticate
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -52,6 +52,7 @@ export class MoreScreen extends UIElement {
|
||||||
|
|
||||||
return new VerticalCombine([
|
return new VerticalCombine([
|
||||||
tr.intro,
|
tr.intro,
|
||||||
|
tr.requestATheme,
|
||||||
new VerticalCombine(els),
|
new VerticalCombine(els),
|
||||||
tr.streetcomplete
|
tr.streetcomplete
|
||||||
]).Render();
|
]).Render();
|
||||||
|
|
|
@ -924,6 +924,12 @@ export default class Translations {
|
||||||
fr: "<h3>Plus de thème </h3>Vous aimez collecter des données? <br/>Il y a plus de thèmes disponible.",
|
fr: "<h3>Plus de thème </h3>Vous aimez collecter des données? <br/>Il y a plus de thèmes disponible.",
|
||||||
nl: "<h3>Meer thema's</h3>Vind je het leuk om geodata te verzamelen? <br/> Hier vind je meer opties."
|
nl: "<h3>Meer thema's</h3>Vind je het leuk om geodata te verzamelen? <br/> Hier vind je meer opties."
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
requestATheme: new T({
|
||||||
|
en: "If you want a custom-built quest, request it <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>here</a>",
|
||||||
|
nl: "Wil je een eigen kaartthema, vraag dit <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>hier aan</a>"
|
||||||
|
}),
|
||||||
|
|
||||||
streetcomplete: new T({
|
streetcomplete: new T({
|
||||||
en: "Another, similar application is <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>",
|
en: "Another, similar application is <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>",
|
||||||
fr: "Une autre application similaire est <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>",
|
fr: "Une autre application similaire est <a href='https://play.google.com/store/apps/details?id=de.westnordost.streetcomplete' target='_blank'>StreetComplete</a>",
|
||||||
|
|
|
@ -54,6 +54,10 @@ form {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected-element {
|
||||||
|
fill: black
|
||||||
|
}
|
||||||
|
|
||||||
/**************** GENERIC ****************/
|
/**************** GENERIC ****************/
|
||||||
|
|
||||||
.uielement {
|
.uielement {
|
||||||
|
|
2
index.ts
2
index.ts
|
@ -186,7 +186,7 @@ const bm = new Basemap("leafletDiv", locationControl, new VariableUiElement(
|
||||||
|
|
||||||
const layerSetup = InitUiElements.InitLayers(layoutToUse, osmConnection, changes, allElements, bm, fullScreenMessage, selectedElement);
|
const layerSetup = InitUiElements.InitLayers(layoutToUse, osmConnection, changes, allElements, bm, fullScreenMessage, selectedElement);
|
||||||
|
|
||||||
const layerUpdater = new LayerUpdater(bm, layerSetup.minZoom, layerSetup.flayers);
|
const layerUpdater = new LayerUpdater(bm, layerSetup.minZoom, layoutToUse.widenFactor, layerSetup.flayers);
|
||||||
|
|
||||||
|
|
||||||
// --------------- Setting up layer selection ui --------
|
// --------------- Setting up layer selection ui --------
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue