Make imageCarousel fit in with other elements (to make images optional or lower in the popup), add ghost bike popup

This commit is contained in:
Pieter Vander Vennet 2020-07-14 20:18:44 +02:00
parent 5970883adc
commit 54a01dfbef
15 changed files with 289 additions and 57 deletions

View file

@ -2,7 +2,7 @@ import {LayerDefinition} from "../LayerDefinition";
import {And, Or, Tag} from "../../Logic/TagsFilter";
import {OperatorTag} from "../Questions/OperatorTag";
import * as L from "leaflet";
import FixedName from "../Questions/FixedName";
import FixedText from "../Questions/FixedText";
import { BikeParkingType } from "../Questions/BikeParkingType";
export class BikeParkings extends LayerDefinition {
@ -26,7 +26,7 @@ export class BikeParkings extends LayerDefinition {
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new FixedName("fietsparking");
this.title = new FixedText("fietsparking");
this.elementsToShow = [
new OperatorTag(),
new BikeParkingType()

View file

@ -3,7 +3,8 @@ import {And, Or, Tag} from "../../Logic/TagsFilter";
import {OperatorTag} from "../Questions/OperatorTag";
import * as L from "leaflet";
import { PumpManual } from "../Questions/PumpManual";
import FixedName from "../Questions/FixedName";
import FixedText from "../Questions/FixedText";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
export class BikePumps extends LayerDefinition {
@ -14,24 +15,25 @@ export class BikePumps extends LayerDefinition {
this.overpassFilter = new Or([
new And([
new Tag("amenity", "compressed_air"),
new Tag("bicycle", "yes"),
new Tag("amenity", "bicycle_repair_station"),
new Tag("service:bicycle:pump", "yes"),
])
]
);
this.newElementTags = [
new Tag("amenity", "compressed_air"),
new Tag("bicycle", "yes"),
new Tag("amenity", "bicycle_repair_station"),
new Tag("service:bicycle:pump", "yes"),
// new Tag("fixme", "Toegevoegd met MapComplete, geometry nog uit te tekenen")
];
this.maxAllowedOverlapPercentage = 10;
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new FixedName("pomp");
this.title = new FixedText("Pomp");
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
// new NameQuestion(),
// new AccessTag(),
new OperatorTag(),

View file

@ -7,6 +7,7 @@ import {TagRenderingOptions} from "../TagRendering";
import {NameQuestion} from "../Questions/NameQuestion";
import {NameInline} from "../Questions/NameInline";
import {DescriptionQuestion} from "../Questions/DescriptionQuestion";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
export class Bos extends LayerDefinition {
@ -33,6 +34,7 @@ export class Bos extends LayerDefinition {
this.style = this.generateStyleFunction();
this.title = new NameInline("bos");
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new NameQuestion(),
new AccessTag(),
new OperatorTag(),

View file

@ -0,0 +1,36 @@
import {LayerDefinition} from "../LayerDefinition";
import {Tag} from "../../Logic/TagsFilter";
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
import {TagRenderingOptions} from "../TagRendering";
import FixedText from "../Questions/FixedText";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
import L from "leaflet";
export class GhostBike extends LayerDefinition {
constructor() {
super();
this.name = "ghost bike";
this.overpassFilter = new Tag("memorial", "ghost_bike")
this.title = new FixedText("Ghost bike");
this.elementsToShow = [
new FixedText("A <b>ghost bike</b> is a memorial for a cyclist who died in a traffic accident," +
" in the form of a white bicycle placed permanently near the accident location."),
new ImageCarouselWithUploadConstructor(),
];
this.style = (tags: any) => {
return {
color: "#000000",
icon: L.icon({
iconUrl: 'assets/ghost_bike.svg',
iconSize: [40, 40],
iconAnchor: [20, 20],
})
}
};
}
}

View file

@ -6,6 +6,7 @@ import {OperatorTag} from "../Questions/OperatorTag";
import {NameQuestion} from "../Questions/NameQuestion";
import {NameInline} from "../Questions/NameInline";
import {DescriptionQuestion} from "../Questions/DescriptionQuestion";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
export class NatureReserves extends LayerDefinition {
@ -23,6 +24,7 @@ export class NatureReserves extends LayerDefinition {
this.title = new NameInline("natuurreservaat");
this.style = this.generateStyleFunction();
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new NameQuestion(),
new AccessTag(),
new OperatorTag(),

View file

@ -7,6 +7,7 @@ import {TagRenderingOptions} from "../TagRendering";
import {NameQuestion} from "../Questions/NameQuestion";
import {NameInline} from "../Questions/NameInline";
import {DescriptionQuestion} from "../Questions/DescriptionQuestion";
import {ImageCarouselWithUploadConstructor} from "../../UI/Image/ImageCarouselWithUpload";
export class Park extends LayerDefinition {
@ -58,6 +59,7 @@ export class Park extends LayerDefinition {
this.style = this.generateStyleFunction();
this.title = new NameInline("park");
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new NameQuestion(),
this.accessByDefault,
this.operatorByDefault,

View file

@ -2,13 +2,14 @@ import {Layout} from "../Layout";
import {GrbToFix} from "../Layers/GrbToFix";
import { BikePumps } from "../Layers/BikePumps";
import { BikeParkings } from "../Layers/BikeParkings";
import {GhostBike} from "../Layers/GhostBike";
export default class Cyclofix extends Layout {
constructor() {
super(
"pomp",
"Grb import fix tool",
[new BikePumps(), new BikeParkings()],
[new BikePumps(), new BikeParkings(), new GhostBike()],
15,
51.2083,
3.2279,

View file

@ -1,6 +1,6 @@
import { TagRenderingOptions } from "../TagRendering";
export default class FixedName extends TagRenderingOptions {
export default class FixedText extends TagRenderingOptions {
constructor(category: string) {
super({
mappings: [

View file

@ -13,7 +13,6 @@ export class UserDetails {
public osmConnection: OsmConnection;
public dryRun: boolean;
home: { lon: number; lat: number };
}
export class OsmConnection {
@ -121,6 +120,27 @@ export class OsmConnection {
}
public preferences = new UIEventSource<any>({});
public preferenceSources : any = {}
public GetPreference(key: string) : UIEventSource<string>{
if(this.preferenceSources[key] !== undefined){
return this.preferenceSources[key];
}
const pref = new UIEventSource<string>(undefined);
pref.addCallback((v) => {
this.SetPreference(key, v);
});
this.preferences.addCallback((prefs) => {
if (prefs[key] !== undefined) {
pref.setData(prefs[key]);
}
});
this.preferenceSources[key] = pref;
return pref;
}
private UpdatePreferences() {
const self = this;
this.auth.xhr({
@ -142,7 +162,7 @@ export class OsmConnection {
});
}
public SetPreference(k:string, v:string) {
private SetPreference(k:string, v:string) {
if(!this.userDetails.data.loggedIn){
console.log("Not saving preference: user not logged in");
return;

View file

@ -94,3 +94,6 @@ Trash icon by Dave Gandy, CC-BY-SA
https://commons.wikimedia.org/wiki/File:Home-icon.svg
Home icon by Timothy Miller, CC-BY-SA 3.0
https://commons.wikimedia.org/wiki/File:Map_icons_by_Scott_de_Jonge_-_bicycle-store.svg
Bicycle logo, Scott de Jonge

View file

@ -15,29 +15,25 @@ import {TagDependantUIElement} from "../Customizations/UIElementConstructor";
export class FeatureInfoBox extends UIElement {
private _tagsES: UIEventSource<any>;
private _changes: Changes;
private _userDetails: UIEventSource<UserDetails>;
private _title: UIElement;
private _osmLink: UIElement;
private _questions: QuestionPicker;
private _changes: Changes;
private _userDetails: UIEventSource<UserDetails>;
private _imageElement: ImageCarousel;
private _pictureUploader: UIElement;
private _wikipedialink: UIElement;
private _infoboxes: TagDependantUIElement[];
private _infoboxes: TagDependantUIElement[];
private _questions: QuestionPicker;
constructor(
tagsES: UIEventSource<any>,
title: TagRenderingOptions,
elementsToShow: TagRenderingOptions[],
changes: Changes,
userDetails: UIEventSource<UserDetails>,
preferedPictureLicense: UIEventSource<string>
userDetails: UIEventSource<UserDetails>
) {
super(tagsES);
this._tagsES = tagsES;
@ -45,9 +41,9 @@ export class FeatureInfoBox extends UIElement {
this._userDetails = userDetails;
this.ListenTo(userDetails);
this._imageElement = new ImageCarousel(this._tagsES, changes);
this._infoboxes = [];
elementsToShow = elementsToShow ?? []
for (const tagRenderingOption of elementsToShow) {
this._infoboxes.push(
tagRenderingOption.construct(this._tagsES, this._changes));
@ -60,11 +56,9 @@ export class FeatureInfoBox extends UIElement {
)
this._title = new TagRenderingOptions(title.options).construct(this._tagsES, this._changes);
this._osmLink =new OsmLink().construct(this._tagsES, this._changes);
this._wikipedialink = new WikipediaLink().construct(this._tagsES, this._changes);
this._pictureUploader = new OsmImageUploadHandler(tagsES, userDetails, preferedPictureLicense,
changes, this._imageElement.slideshow).getUI();
}
@ -110,10 +104,6 @@ export class FeatureInfoBox extends UIElement {
"</div>" +
"<div class='infoboxcontents'>" +
this._imageElement.Render() +
this._pictureUploader.Render() +
new VerticalCombine(info, "infobox-information ").Render() +
questionsHtml +
@ -126,8 +116,6 @@ export class FeatureInfoBox extends UIElement {
Activate() {
super.Activate();
this._imageElement.Activate();
this._pictureUploader.Activate();
for (const infobox of this._infoboxes) {
infobox.Activate();
}
@ -135,8 +123,6 @@ export class FeatureInfoBox extends UIElement {
Update() {
super.Update();
this._imageElement.Update();
this._pictureUploader.Update();
this._title.Update();
for (const infobox of this._infoboxes) {
infobox.Update();

View file

@ -8,8 +8,29 @@ import {Changes} from "../../Logic/Changes";
import {VariableUiElement} from "../Base/VariableUIElement";
import {ConfirmDialog} from "../ConfirmDialog";
import {UserDetails} from "../../Logic/OsmConnection";
import {TagDependantUIElement, TagDependantUIElementConstructor} from "../../Customizations/UIElementConstructor";
export class ImageCarouselConstructor implements TagDependantUIElementConstructor{
IsKnown(properties: any): boolean {
return true;
}
IsQuestioning(properties: any): boolean {
return false;
}
Priority(): number {
return 0;
}
construct(tags: UIEventSource<any>, changes: Changes): TagDependantUIElement {
return new ImageCarousel(tags, changes);
}
}
export class ImageCarousel extends TagDependantUIElement {
export class ImageCarousel extends UIElement {
private readonly searcher: ImageSearcher;
@ -98,6 +119,18 @@ export class ImageCarousel extends UIElement {
"</span>";
}
IsKnown(): boolean {
return true;
}
IsQuestioning(): boolean {
return false;
}
Priority(): number {
return 0;
}
InnerUpdate(htmlElement: HTMLElement) {
super.InnerUpdate(htmlElement);
this._deleteButton.Update();

View file

@ -0,0 +1,71 @@
import {TagDependantUIElement, TagDependantUIElementConstructor} from "../../Customizations/UIElementConstructor";
import {ImageCarousel} from "./ImageCarousel";
import {OsmImageUploadHandler} from "../../Logic/OsmImageUploadHandler";
import {UIEventSource} from "../UIEventSource";
import {Changes} from "../../Logic/Changes";
import {UserDetails} from "../../Logic/OsmConnection";
import {ImageUploadFlow} from "../ImageUploadFlow";
export class ImageCarouselWithUploadConstructor implements TagDependantUIElementConstructor{
IsKnown(properties: any): boolean {
return true;
}
IsQuestioning(properties: any): boolean {
return false;
}
Priority(): number {
return 0;
}
construct(tags: UIEventSource<any>, changes: Changes): TagDependantUIElement {
return new ImageCarouselWithUpload(tags, changes);
}
}
class ImageCarouselWithUpload extends TagDependantUIElement {
private _imageElement: ImageCarousel;
private _pictureUploader: ImageUploadFlow;
constructor(tags: UIEventSource<any>, changes: Changes) {
super(tags);
this._imageElement = new ImageCarousel(tags, changes);
const userDetails = changes.login.userDetails;
const license = changes.login.GetPreference( "mapcomplete-pictures-license");
this._pictureUploader = new OsmImageUploadHandler(tags,
userDetails, license,
changes, this._imageElement.slideshow).getUI();
}
protected InnerRender(): string {
return this._imageElement.Render() +
this._pictureUploader.Render();
}
Activate() {
super.Activate();
this._imageElement.Activate();
this._pictureUploader.Activate();
}
Update() {
super.Update();
this._imageElement.Update();
this._pictureUploader.Update();
}
IsKnown(): boolean {
return true;
}
IsQuestioning(): boolean {
return false;
}
Priority(): number {
return 0;
}
}

92
assets/ghost_bike.svg Normal file
View file

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
version="2"
width="50"
height="50"
viewBox="0 0 50 50"
id="svg4"
sodipodi:docname="ghost_bike.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata10">
<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>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1001"
id="namedview6"
showgrid="false"
inkscape:zoom="4.72"
inkscape:cx="-40.53625"
inkscape:cy="33.532739"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="background"
sodipodi:insensitive="true">
<ellipse
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:50;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path839"
cx="25"
cy="24.894068"
rx="25"
ry="25.105932" />
</g>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="bicycle">
<path
d="m 37.198846,28.51624 c -0.865699,0 -1.688316,0.177789 -2.435717,0.497127 l -2.103385,-3.60434 1.58506,-2.71676 c 0.215399,-0.370622 0.09027,-0.846552 -0.279675,-1.063319 -0.162747,-0.09437 -0.343955,-0.265316 -0.515591,-0.237279 l -0.134709,-0.158644 h -3.109265 c -0.428746,0 -0.776803,0.596963 -0.776803,1.02571 0,0.429429 0.348057,1.025708 0.776803,1.025708 h 2.015176 l -0.90741,1.367611 h -9.079572 l 1.813452,-3.419029 h 0.718681 c 0.428746,0 0.776802,-0.254375 0.776802,-0.683806 0,-0.42943 -0.348056,-0.683806 -0.776802,-0.683806 h -3.886069 c -0.428061,0 -0.776803,0.254376 -0.776803,0.683806 0,0.429431 0.348057,0.683806 0.776803,0.683806 h 1.366929 l -4.368835,7.634691 c -0.748084,-0.319337 -1.572071,-0.423959 -2.437085,-0.423959 -3.432704,0 -6.2157926,2.820014 -6.2157926,6.252718 0,3.433389 2.7830886,6.234257 6.2164776,6.234257 3.433388,0 6.216478,-2.774199 6.216478,-6.207588 0,-2.010389 -0.958697,-3.788967 -2.441187,-4.926136 l 1.663699,-2.848735 4.768861,8.17558 0.01847,0.02598 0.02051,0.03077 0.01572,0.02325 0.06154,0.07111 0.0076,0.0089 0.0212,0.01915 0.02188,0.01777 0.06017,0.04787 0.0253,0.01641 0.01983,0.01298 0.0082,0.0048 0.0027,0.0027 0.06564,0.03214 0.0076,0.0033 0.01573,0.0082 0.0054,0.0014 0.04992,0.01778 0.0465,0.01505 0.0095,0.0027 0.01709,0.0027 0.03008,0.0062 0.139496,0.01436 6.84e-4,0.04239 0.0027,0.04034 h 4.712106 c 0.384299,2.735223 2.9937,5.398646 6.16314,5.398646 3.433388,0 6.216478,-2.804288 6.216478,-6.237676 6.83e-4,-3.432704 -2.782407,-6.236991 -6.215794,-6.236991 z m -17.095143,6.216477 c 0,2.575896 -2.086974,4.662872 -4.662187,4.662872 -2.575213,0 -4.662188,-2.087659 -4.662188,-4.662872 0,-2.574528 2.086975,-4.661503 4.662188,-4.661503 0.579183,0 1.131698,0.110088 1.643185,0.30361 l -2.314683,3.96744 c -0.216082,0.369938 -0.09027,0.845868 0.280362,1.063319 0.123084,0.07111 0.257794,0.10531 0.390451,0.10531 0.267369,0 0.527215,-0.13813 0.672182,-0.384984 l 2.315367,-3.970175 c 1.022972,0.855441 1.675323,2.140312 1.675323,3.576987 z m 6.216477,-1.708146 -4.086422,-7.004905 h 8.173529 z m 5.438991,-5.938853 1.664383,2.918483 c -1.286923,0.987416 -2.17587,2.169715 -2.38785,4.221133 h -3.362956 z m 2.452811,4.338747 1.634979,2.800869 H 32.60709 c 0.187363,-1.367612 0.769965,-2.102702 1.604892,-2.800869 z m 2.986864,8.01352 c -2.309212,0 -4.222501,-1.793624 -4.592439,-3.84504 h 4.590387 l 0.0033,-0.04035 0.138811,-0.03624 0.03145,-0.01572 0.129239,-0.04513 0.01436,-0.01089 0.07727,-0.03966 0.01847,-0.01436 0.06907,-0.04992 0.05334,-0.04513 0.05197,-0.05675 0.0465,-0.05813 0.03898,-0.06292 0.03556,-0.06496 0.02667,-0.07111 0.0212,-0.07111 0.01164,-0.07111 0.0089,-0.08411 0.002,-0.02394 -0.0033,-0.04377 -0.0095,-0.0848 -0.01573,-0.07248 -0.02257,-0.07111 -0.03556,-0.07726 -0.01847,-0.04035 -2.314683,-3.96744 c 0.512856,-0.193517 1.064686,-0.30361 1.643186,-0.30361 2.575896,0 4.662871,2.108172 4.662871,4.682701 6.83e-4,2.575896 -2.086975,4.684753 -4.662871,4.684753 z"
id="path2"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.6838057"
inkscape:connector-curvature="0" />
<g
id="g861"
transform="translate(-10.037321,-26.552854)">
<path
inkscape:connector-curvature="0"
id="path842"
d="M 25.018397,35.018924 V 47.003785"
style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path842-3"
d="M 28.86857,39.213625 H 20.748791"
style="fill:none;stroke:#ffffff;stroke-width:1.64621139;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="layer3"
inkscape:label="cross" />
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -102,7 +102,6 @@ const leftMessage = new UIEventSource<() => UIElement>(undefined);
const selectedElement = new UIEventSource<any>(undefined);
const preferedPictureLicense = new UIEventSource<string>(undefined);
const locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({
zoom: questSetToRender.startzoom,
@ -137,21 +136,6 @@ const bm = new Basemap("leafletDiv", locationControl, new VariableUiElement(
));
// ------------- Tie together user settings and UI -----------
const picturesPrefName = "mapcomplete-pictures-license";
preferedPictureLicense.addCallback((license) => {
osmConnection.SetPreference(picturesPrefName, license);
});
osmConnection.preferences.addCallback((prefs) => {
if (prefs[picturesPrefName] !== undefined) {
preferedPictureLicense.setData(prefs[picturesPrefName]);
}
})
// ------------- Setup the layers -------------------------------
const addButtons: {
@ -175,8 +159,7 @@ for (const layer of questSetToRender.layers) {
layer.title,
layer.elementsToShow,
changes,
osmConnection.userDetails,
preferedPictureLicense
osmConnection.userDetails
)
};
@ -228,8 +211,7 @@ selectedElement.addCallback((data) => {
layer.title,
layer.elementsToShow,
changes,
osmConnection.userDetails,
preferedPictureLicense
osmConnection.userDetails
));
break;
}