More fancyness, less bugs

This commit is contained in:
Pieter Vander Vennet 2020-11-17 16:29:51 +01:00
parent 16612b10ef
commit 2177db376c
27 changed files with 821 additions and 607 deletions

View file

@ -11,7 +11,7 @@ import Svg from "../../Svg";
import {SubstitutedTranslation} from "../../UI/SpecialVisualizations"; import {SubstitutedTranslation} from "../../UI/SpecialVisualizations";
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
import Combine from "../../UI/Base/Combine"; import Combine from "../../UI/Base/Combine";
import {Browser} from "leaflet"; import {VariableUiElement} from "../../UI/Base/VariableUIElement";
export default class LayerConfig { export default class LayerConfig {
@ -56,7 +56,8 @@ export default class LayerConfig {
tagRenderings: TagRenderingConfig []; tagRenderings: TagRenderingConfig [];
constructor(json: LayerConfigJson, context?: string) { constructor(json: LayerConfigJson, roamingRenderings: TagRenderingConfig[],
context?: string) {
context = context + "." + json.id; context = context + "." + json.id;
this.id = json.id; this.id = json.id;
@ -140,7 +141,7 @@ export default class LayerConfig {
} }
public GenerateLeafletStyle(tags: any): public GenerateLeafletStyle(tags: any, clickable: boolean):
{ {
color: string; color: string;
icon: { icon: {
@ -149,7 +150,8 @@ export default class LayerConfig {
iconAnchor: [number, number]; iconAnchor: [number, number];
iconSize: [number, number]; iconSize: [number, number];
html: string; html: string;
rotation: number; rotation: string;
className?: string;
}; };
weight: number; dashArray: number[] weight: number; dashArray: number[]
} { } {
@ -186,7 +188,7 @@ export default class LayerConfig {
} }
const weight = rendernum(this.width, 5); const weight = rendernum(this.width, 5);
const rotation = rendernum(this.rotation, 0); const rotation = render(this.rotation, "0deg");
const iconW = num(iconSize[0]); const iconW = num(iconSize[0]);
@ -209,12 +211,14 @@ export default class LayerConfig {
anchorH = iconH; anchorH = iconH;
} }
let html = `<img src="${iconUrl}" style="width:100%;height:100%;rotate:${rotation}deg;display:block;" />`;
let html = `<img src="${iconUrl}" style="width:100%;height:100%;rotate:${rotation};display:block;" />`;
if (iconUrl.startsWith(Utils.assets_path)) { if (iconUrl.startsWith(Utils.assets_path)) {
const key = iconUrl.substr(Utils.assets_path.length); const key = iconUrl.substr(Utils.assets_path.length);
html = new Combine([ html = new Combine([
(Svg.All[key] as string).replace(/stop-color:#000000/g, 'stop-color:' + color) (Svg.All[key] as string).replace(/stop-color:#000000/g, 'stop-color:' + color)
]).SetStyle(`width:100%;height:100%;rotate:${rotation}deg;display:block;`).Render(); ]).SetStyle(`width:100%;height:100%;rotate:${rotation};display:block;`).Render();
} }
return { return {
icon: icon:
@ -224,7 +228,8 @@ export default class LayerConfig {
iconAnchor: [anchorW, anchorH], iconAnchor: [anchorW, anchorH],
popupAnchor: [0, 3 - anchorH], popupAnchor: [0, 3 - anchorH],
rotation: rotation, rotation: rotation,
iconUrl: iconUrl iconUrl: iconUrl,
className: clickable ? "leaflet-div-icon" : "leaflet-div-icon unclickable"
}, },
color: color, color: color,
weight: weight, weight: weight,

View file

@ -66,7 +66,8 @@ export interface LayerConfigJson {
*/ */
iconSize?: string | TagRenderingConfigJson; iconSize?: string | TagRenderingConfigJson;
/** /**
* The rotation of an icon, useful for e.g. directions * The rotation of an icon, useful for e.g. directions.
* Usage: as if it were a css property for 'rotate', thus has to end with 'deg', e.g. `90deg`, `{direction}deg`, `calc(90deg - {camera:direction}deg)``
*/ */
rotation?: string | TagRenderingConfigJson; rotation?: string | TagRenderingConfigJson;

View file

@ -80,7 +80,7 @@ export default class LayoutConfig {
} else { } else {
throw "Unkown fixed layer " + layer; throw "Unkown fixed layer " + layer;
} }
return new LayerConfig(layer, `${this.id}.layers[${i}]`); return new LayerConfig(layer, this.roamingRenderings,`${this.id}.layers[${i}]`);
}); });
this.hideFromOverview = json.hideFromOverview ?? false; this.hideFromOverview = json.hideFromOverview ?? false;

View file

@ -14,6 +14,7 @@ import * as bike_cleaning from "../assets/layers/bike_cleaning/bike_cleaning.jso
import * as maps from "../assets/layers/maps/maps.json" import * as maps from "../assets/layers/maps/maps.json"
import * as information_boards from "../assets/layers/information_board/information_board.json" import * as information_boards from "../assets/layers/information_board/information_board.json"
import * as direction from "../assets/layers/direction/direction.json" import * as direction from "../assets/layers/direction/direction.json"
import * as surveillance_camera from "../assets/layers/surveillance_cameras/surveillance_cameras.json"
import LayerConfig from "./JSON/LayerConfig"; import LayerConfig from "./JSON/LayerConfig";
export default class SharedLayers { export default class SharedLayers {
@ -25,21 +26,22 @@ export default class SharedLayers {
private static getSharedLayers(){ private static getSharedLayers(){
const sharedLayersList = [ const sharedLayersList = [
new LayerConfig(drinkingWater, "shared_layers"), new LayerConfig(drinkingWater,[], "shared_layers"),
new LayerConfig(ghostbikes, "shared_layers"), new LayerConfig(ghostbikes,[], "shared_layers"),
new LayerConfig(viewpoint, "shared_layers"), new LayerConfig(viewpoint,[], "shared_layers"),
new LayerConfig(bike_parking, "shared_layers"), new LayerConfig(bike_parking,[], "shared_layers"),
new LayerConfig(bike_repair_station, "shared_layers"), new LayerConfig(bike_repair_station,[], "shared_layers"),
new LayerConfig(bike_monitoring_station, "shared_layers"), new LayerConfig(bike_monitoring_station,[], "shared_layers"),
new LayerConfig(birdhides, "shared_layers"), new LayerConfig(birdhides,[], "shared_layers"),
new LayerConfig(nature_reserve, "shared_layers"), new LayerConfig(nature_reserve,[], "shared_layers"),
new LayerConfig(bike_cafes, "shared_layers"), new LayerConfig(bike_cafes,[], "shared_layers"),
new LayerConfig(cycling_themed_objects, "shared_layers"), new LayerConfig(cycling_themed_objects,[], "shared_layers"),
new LayerConfig(bike_shops, "shared_layers"), new LayerConfig(bike_shops,[], "shared_layers"),
new LayerConfig(bike_cleaning, "shared_layers"), new LayerConfig(bike_cleaning,[], "shared_layers"),
new LayerConfig(maps, "shared_layers"), new LayerConfig(maps,[], "shared_layers"),
new LayerConfig(direction, "shared_layers"), new LayerConfig(direction,[], "shared_layers"),
new LayerConfig(information_boards, "shared_layers") new LayerConfig(information_boards,[], "shared_layers"),
new LayerConfig(surveillance_camera,[], "shared_layers")
]; ];
const sharedLayers = new Map<string, LayerConfig>(); const sharedLayers = new Map<string, LayerConfig>();

View file

@ -129,88 +129,65 @@ export class FilteredLayer {
let self = this; let self = this;
this._geolayer = L.geoJSON(data, { this._geolayer = L.geoJSON(data, {
style: feature => style: feature =>
self.layerDef.GenerateLeafletStyle(feature.properties), self.layerDef.GenerateLeafletStyle(feature.properties, self._showOnPopup !== undefined),
pointToLayer: function (feature, latLng) { pointToLayer: function (feature, latLng) {
// Point to layer converts the 'point' to a layer object - as the geojson layer natively cannot handle points // Point to layer converts the 'point' to a layer object - as the geojson layer natively cannot handle points
// Click handling is done in the next step // Click handling is done in the next step
const style = self.layerDef.GenerateLeafletStyle(feature.properties); const style = self.layerDef.GenerateLeafletStyle(feature.properties, self._showOnPopup !== undefined);
let marker; let marker;
if (style.icon === undefined) { if (style.icon === undefined) {
marker = L.circle(latLng, { marker = L.circle(latLng, {
radius: 25, radius: 25,
color: style.color color: style.color
}); });
} else if (style.icon.iconUrl.startsWith("$circle")) { } else if (style.icon.iconUrl.startsWith("$circle")) {
marker = L.circle(latLng, { marker = L.circle(latLng, {
radius: 25, radius: 25,
color: style.color color: style.color
}); });
} else { } else {
marker = L.marker(latLng, { marker = L.marker(latLng, {
icon: L.divIcon(style.icon) icon: L.divIcon(style.icon)
});
}
return marker;
},
onEachFeature: function (feature, layer: Layer) {
if (self._showOnPopup === undefined) {
// No popup contents defined -> don't do anything
return;
}
function openPopup(latlng: any) {
if (layer.getPopup() === undefined
&& (window.screen.availHeight > 600 || window.screen.availWidth > 600) // We DON'T trigger this code on small screens! No need to create a popup
) {
const popup = L.popup({
autoPan: true,
closeOnEscapeKey: true,
}, layer);
popup.setLatLng(latlng)
layer.bindPopup(popup);
const eventSource = State.state.allElements.addOrGetElement(feature);
const uiElement = self._showOnPopup(eventSource, feature);
// We first render the UIelement (which'll still need an update later on...)
// But at least it'll be visible already
popup.setContent(uiElement.Render());
popup.openOn(State.state.bm.map);
// popup.openOn(State.state.bm.map);
// ANd we perform the pending update
uiElement.Update();
// @ts-ignore
popup.Update = () => {
uiElement.Update();
}
} else {
// @ts-ignore
layer.getPopup().Update();
}
// We set the element as selected...
State.state.selectedElement.setData(feature);
}
layer.on("click", (e) => {
// @ts-ignore
openPopup(e.latlng);
// We mark the event as consumed
L.DomEvent.stop(e);
}); });
if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) {
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
openPopup({lat: center[1], lng: center[0]})
}
} }
return marker;
},
onEachFeature: function (feature, layer: Layer) {
if (self._showOnPopup === undefined) {
// No popup contents defined -> don't do anything
return;
}
const popup = L.popup({
autoPan: true,
closeOnEscapeKey: true,
}, layer);
let uiElement: UIElement;
const eventSource = State.state.allElements.addOrGetElement(feature);
uiElement = self._showOnPopup(eventSource, feature);
popup.setContent(uiElement.Render());
layer.bindPopup(popup);
// We first render the UIelement (which'll still need an update later on...)
// But at least it'll be visible already
layer.on("click", (e) => {
// We set the element as selected...
State.state.selectedElement.setData(feature);
uiElement.Update();
});
if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) {
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
popup.setLatLng({lat: center[1], lng: center[0]});
popup.openOn(State.state.bm.map)
}
}
}); });
if (this.combinedIsDisplayed.data) { if (this.combinedIsDisplayed.data) {

View file

@ -82,7 +82,7 @@ export default class MetaTagging {
}) })
) )
private static isOpen = new SimpleMetaTagger( private static isOpen = new SimpleMetaTagger(
["_isOpen", "_isOpen:description"], "If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no", ["_isOpen", "_isOpen:description"], "If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no')",
(feature => { (feature => {
const tagsSource = State.state.allElements.addOrGetElement(feature); const tagsSource = State.state.allElements.addOrGetElement(feature);
tagsSource.addCallback(tags => { tagsSource.addCallback(tags => {
@ -123,16 +123,40 @@ export default class MetaTagging {
}) })
) )
public static carriageWayWidth = new SimpleMetaTagger( private static directionSimplified = new SimpleMetaTagger(
["_width:needed","_width:needed:no_pedestrians", "_width:difference"], ["_direction:simplified", "_direction:leftright"], "_direction:simplified turns 'camera:direction' and 'direction' into either 0, 45, 90, 135, 180, 225, 270 or 315, whichever is closest. _direction:leftright is either 'left' or 'right', which is left-looking on the map or 'right-looking' on the map",
(feature => {
const tags = feature.properties;
const direction = tags["camera:direction"] ?? tags["direction"];
if (direction === undefined) {
return;
}
let n = Number(direction);
if (isNaN(n)) {
return;
}
// [22.5 -> 67.5] is sector 1
// [67.5 -> ] is sector 1
n = (n + 22.5) % 360;
n = Math.floor(n / 45);
tags["_direction:simplified"] = n;
tags["_direction:leftright"] = n <= 3 ? "right" : "left";
})
)
private static carriageWayWidth = new SimpleMetaTagger(
["_width:needed", "_width:needed:no_pedestrians", "_width:difference"],
"Legacy for a specific project calculating the needed width for safe traffic on a road. Only activated if 'width:carriageway' is present", "Legacy for a specific project calculating the needed width for safe traffic on a road. Only activated if 'width:carriageway' is present",
(feature: any, index: number) => { (feature: any, index: number) => {
const properties = feature.properties; const properties = feature.properties;
if(properties["width:carriageway"] === undefined){ if (properties["width:carriageway"] === undefined) {
return; return;
} }
const carWidth = 2; const carWidth = 2;
const cyclistWidth = 1.5; const cyclistWidth = 1.5;
const pedestrianWidth = 0.75; const pedestrianWidth = 0.75;
@ -239,7 +263,8 @@ export default class MetaTagging {
MetaTagging.surfaceArea, MetaTagging.surfaceArea,
MetaTagging.country, MetaTagging.country,
MetaTagging.isOpen, MetaTagging.isOpen,
MetaTagging.carriageWayWidth MetaTagging.carriageWayWidth,
MetaTagging.directionSimplified
]; ];

View file

@ -136,6 +136,7 @@ export class UpdateFromOverpass {
const self = this; const self = this;
window?.setTimeout( window?.setTimeout(
function () { function () {
self.runningQuery.setData(false)
self.update(state) self.update(state)
}, this.retries.data * 5000 }, this.retries.data * 5000
) )

View file

@ -56,8 +56,8 @@ export class Imgur {
}, },
}; };
$.ajax(settings).done(function (response) { $.ajax(settings).done(function (response) {
const descr : string= response.data.description; const descr: string = response.data.description ?? "";
const data : any = {}; const data: any = {};
for (const tag of descr.split("\n")) { for (const tag of descr.split("\n")) {
const kv = tag.split(":"); const kv = tag.split(":");
const k = kv[0]; const k = kv[0];

View file

@ -23,7 +23,7 @@ export default class State {
// The singleton of the global state // The singleton of the global state
public static state: State; public static state: State;
public static vNumber = "0.1.3-rc4"; public static vNumber = "0.1.3-rc5";
// 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 = {

4
Svg.ts
View file

@ -64,7 +64,7 @@ export default class Svg {
public static crosshair_blue_svg() { return new FixedUiElement(Svg.crosshair_blue);} public static crosshair_blue_svg() { return new FixedUiElement(Svg.crosshair_blue);}
public static crosshair_blue_ui() { return new FixedUiElement(Svg.crosshair_blue_img);} public static crosshair_blue_ui() { return new FixedUiElement(Svg.crosshair_blue_img);}
public static crosshair = " <!-- 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\" inkscape:version=\"0.92.4 (5da689c313, 2019-01-14)\" sodipodi:docname=\"crosshair.svg\"> <defs id=\"defs2\" /> <sodipodi:namedview id=\"base\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageopacity=\"0.0\" inkscape:pageshadow=\"2\" inkscape:zoom=\"2\" inkscape:cx=\"12.898245\" inkscape:cy=\"23.072799\" 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=\"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)\"> <circle style=\"fill: none !important;fill-opacity:1;stroke:#555555;stroke-width:2.64583335;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529\" id=\"path815\" cx=\"13.16302\" cy=\"283.77081\" r=\"8.8715391\" /> <path style=\"fill: none !important;stroke:#555555;stroke-width:2.09723878;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" d=\"M 3.2841366,283.77082 H 1.0418969\" id=\"path817\" inkscape:connector-curvature=\"0\" /> <path style=\"fill: none !important;stroke:#555555;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" d=\"M 25.405696,283.77082 H 23.286471\" id=\"path817-3\" inkscape:connector-curvature=\"0\" /> <path style=\"fill: none !important;stroke:#555555;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" d=\"m 13.229167,295.9489 v -2.11763\" id=\"path817-3-6\" inkscape:connector-curvature=\"0\" /> <path style=\"fill: none !important;stroke:#555555;stroke-width:2.11666668;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" d=\"m 13.229167,275.05759 v -3.44507\" id=\"path817-3-6-7\" inkscape:connector-curvature=\"0\" /> <circle style=\"fill:#555555;fill-opacity:0.99004978;stroke:none;stroke-width:2.81138086;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" id=\"path866\" cx=\"13.229166\" cy=\"283.77081\" r=\"3.4070117\" /> </g> </svg> " public static crosshair = " <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\" id=\"svg8\" version=\"1.1\" viewBox=\"0 0 26.458333 26.458334\" height=\"100\" width=\"100\"> <defs id=\"defs2\" /> <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 transform=\"translate(0,-270.54165)\" id=\"layer1\"> <circle r=\"8.8715391\" cy=\"283.77081\" cx=\"13.16302\" id=\"path815\" style=\"fill: none !important;fill-opacity:1;stroke:#000000;stroke-width:2.64583335;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529\" /> <path id=\"path817\" d=\"M 3.2841366,283.77082 H 1.0418969\" style=\"fill: none !important;stroke:#000000;stroke-width:2.09723878;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" /> <path id=\"path817-3\" d=\"M 25.405696,283.77082 H 23.286471\" style=\"fill: none !important;stroke:#000000;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" /> <path id=\"path817-3-6\" d=\"m 13.229167,295.9489 v -2.11763\" style=\"fill: none !important;stroke:#000000;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" /> <path id=\"path817-3-6-7\" d=\"m 13.229167,275.05759 v -3.44507\" style=\"fill: none !important;stroke:#000000;stroke-width:2.11666668;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" /> <circle r=\"3.4070117\" cy=\"283.77081\" cx=\"13.229166\" id=\"path866\" style=\"fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.81138086;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1\" /> </g> </svg> "
public static crosshair_img = Img.AsImageElement(Svg.crosshair) public static crosshair_img = Img.AsImageElement(Svg.crosshair)
public static crosshair_svg() { return new FixedUiElement(Svg.crosshair);} public static crosshair_svg() { return new FixedUiElement(Svg.crosshair);}
public static crosshair_ui() { return new FixedUiElement(Svg.crosshair_img);} public static crosshair_ui() { return new FixedUiElement(Svg.crosshair_img);}
@ -79,7 +79,7 @@ export default class Svg {
public static direction_svg() { return new FixedUiElement(Svg.direction);} public static direction_svg() { return new FixedUiElement(Svg.direction);}
public static direction_ui() { return new FixedUiElement(Svg.direction_img);} public static direction_ui() { return new FixedUiElement(Svg.direction_img);}
public static direction_gradient = " <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:xlink=\"http://www.w3.org/1999/xlink\" width=\"100\" height=\"100\" viewBox=\"0 0 100 100\" version=\"1.1\" id=\"svg8\"> <metadata id=\"metadata8\"> <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=\"defs6\"> <linearGradient id=\"linearGradient820\"> <stop id=\"stop816\" offset=\"0\" style=\"stop-color:#000000;stop-opacity:1;\" /> <stop id=\"stop818\" offset=\"1\" style=\"stop-color:#000000;stop-opacity:0\" /> </linearGradient> <radialGradient gradientUnits=\"userSpaceOnUse\" gradientTransform=\"matrix(1.5439431,-0.01852438,0.02075364,1.7297431,-28.198837,-42.329969)\" r=\"28.883806\" fy=\"53.828533\" fx=\"49.787739\" cy=\"53.828533\" cx=\"49.787739\" id=\"radialGradient828\" xlink:href=\"#linearGradient820\" /> </defs> <path style=\"fill:url(#radialGradient828);fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1\" d=\"M 49.787737,49.857275 20.830626,9.2566092 C 35.979158,-2.144159 60.514289,-3.8195259 78.598237,9.0063685 Z\" id=\"path821\" /> </svg> " public static direction_gradient = " <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:xlink=\"http://www.w3.org/1999/xlink\" 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 100 100\" version=\"1.1\" id=\"svg8\" sodipodi:docname=\"direction_gradient.svg\" inkscape:version=\"0.92.4 (5da689c313, 2019-01-14)\"> <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=\"namedview10\" showgrid=\"false\" showguides=\"true\" inkscape:guide-bbox=\"true\" inkscape:zoom=\"9.44\" inkscape:cx=\"69.372244\" inkscape:cy=\"85.073455\" inkscape:window-x=\"0\" inkscape:window-y=\"0\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"svg8\"> <sodipodi:guide position=\"50,117.79661\" orientation=\"1,0\" id=\"guide819\" inkscape:locked=\"false\" /> <sodipodi:guide position=\"57.627119,50\" orientation=\"0,1\" id=\"guide821\" inkscape:locked=\"false\" /> </sodipodi:namedview> <metadata id=\"metadata8\"> <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> <defs id=\"defs6\"> <linearGradient id=\"linearGradient820\"> <stop id=\"innercolor\" offset=\"0\" style=\"stop-color:#000000;stop-opacity:1;\" /> <stop id=\"outercolor\" offset=\"1\" style=\"stop-color:#000000;stop-opacity:0\" /> </linearGradient> <radialGradient gradientUnits=\"userSpaceOnUse\" gradientTransform=\"matrix(1.5439431,-0.01852438,0.02075364,1.7297431,-27.986574,-42.187244)\" r=\"28.883806\" fy=\"53.828533\" fx=\"49.787739\" cy=\"53.828533\" cx=\"49.787739\" id=\"radialGradient828\" xlink:href=\"#linearGradient820\" /> </defs> <path style=\"fill:url(#radialGradient828);fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1\" d=\"M 50,50 21.042889,9.3993342 C 36.191421,-2.001434 60.726552,-3.6768009 78.8105,9.1490935 Z\" id=\"path821\" inkscape:connector-curvature=\"0\" /> </svg> "
public static direction_gradient_img = Img.AsImageElement(Svg.direction_gradient) public static direction_gradient_img = Img.AsImageElement(Svg.direction_gradient)
public static direction_gradient_svg() { return new FixedUiElement(Svg.direction_gradient);} public static direction_gradient_svg() { return new FixedUiElement(Svg.direction_gradient);}
public static direction_gradient_ui() { return new FixedUiElement(Svg.direction_gradient_img);} public static direction_gradient_ui() { return new FixedUiElement(Svg.direction_gradient_img);}

View file

@ -29,6 +29,8 @@ export default class EditableTagRendering extends UIElement {
this._answer = new TagRenderingAnswer(tags, configuration); this._answer = new TagRenderingAnswer(tags, configuration);
this._answer.SetStyle("width:100%;") this._answer.SetStyle("width:100%;")
this._question = this.GenerateQuestion();
this.dumbMode = false;
if (this._configuration.question !== undefined) { if (this._configuration.question !== undefined) {
if (State.state.featureSwitchUserbadge.data) { if (State.state.featureSwitchUserbadge.data) {
@ -66,7 +68,6 @@ export default class EditableTagRendering extends UIElement {
InnerRender(): string { InnerRender(): string {
if (this._editMode.data) { if (this._editMode.data) {
this._question = this.GenerateQuestion();
return this._question.Render(); return this._question.Render();
} }

View file

@ -21,7 +21,7 @@ export class FeatureInfoBox extends UIElement {
layerConfig: LayerConfig layerConfig: LayerConfig
) { ) {
super(); super();
if(layerConfig === undefined){ if (layerConfig === undefined) {
throw "Undefined layerconfig" throw "Undefined layerconfig"
} }
this._tags = tags; this._tags = tags;
@ -30,7 +30,7 @@ export class FeatureInfoBox extends UIElement {
this._title = layerConfig.title === undefined ? undefined : this._title = layerConfig.title === undefined ? undefined :
new TagRenderingAnswer(tags, layerConfig.title) new TagRenderingAnswer(tags, layerConfig.title)
.SetClass("featureinfobox-title"); .SetClass("featureinfobox-title");
this._titleIcons = new Combine( this._titleIcons = new Combine(
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon))) layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)))
.SetClass("featureinfobox-icons"); .SetClass("featureinfobox-icons");

View file

@ -102,7 +102,20 @@ export default class SpecialVisualizations {
args: { name: string, defaultValue?: string, doc: string }[] args: { name: string, defaultValue?: string, doc: string }[]
}[] = }[] =
[ [{
funcName: "all_tags",
docs: "Prints all key-value pairs of the object - used for debugging",
args: [],
constr: ((tags: UIEventSource<any>) => {
return new VariableUiElement(tags.map(tags => {
const parts = [];
for (const key in tags) {
parts.push(key + "=" + tags[key]);
}
return parts.join("<br/>")
})).SetStyle("border: 1px solid black; border-radius: 1em;padding:1em;display:block;")
})
},
{ {
funcName: "image_carousel", funcName: "image_carousel",
docs: "Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)", docs: "Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)",
@ -170,21 +183,7 @@ export default class SpecialVisualizations {
return new VariableUiElement(source.map(data => data[neededValue] ?? "Loading...")); return new VariableUiElement(source.map(data => data[neededValue] ?? "Loading..."));
} }
}, },
{
funcName: "all_tags",
docs: "Prints all key-value pairs of the object - used for debugging",
args:[],
constr: ((tags: UIEventSource<any>) => {
return new VariableUiElement(tags.map(tags => {
const parts = [];
for (const key in tags) {
parts.push(key+"="+tags[key]);
}
return parts.join("<br/>")
})).SetStyle("border: 1px solid black; border-radius: 1em;padding:1em;display:block;")
})
}
] ]
static HelpMessage: UIElement = SpecialVisualizations.GenHelpMessage(); static HelpMessage: UIElement = SpecialVisualizations.GenHelpMessage();

View file

@ -16,11 +16,11 @@
"tagRenderings": [], "tagRenderings": [],
"icon": "./assets/svg/direction_gradient.svg", "icon": "./assets/svg/direction_gradient.svg",
"rotation": { "rotation": {
"render": "{camera:direction}", "render": "{camera:direction}deg",
"mappings": [ "mappings": [
{ {
"if": "direction~*", "if": "direction~*",
"then": "{direction}" "then": "{direction}deg"
} }
] ]
}, },

View file

@ -0,0 +1,379 @@
{
"id": "surveillance_cameras",
"name": {
"en": "Surveillance camera's",
"nl": "Bewakingscamera's"
},
"minzoom": 12,
"overpassTags": {
"and": [
"man_made=surveillance",
{
"or": [
"surveillance:type=camera",
"surveillance:type=ALPR",
"surveillance:type=ANPR"
]
}
]
},
"title": {
"render": {
"en": "Surveillance Camera",
"nl": "Bewakingscamera"
}
},
"description": {},
"tagRenderings": [
"images",
{
"#": "Camera type: fixed; panning; dome",
"question": {
"en": "What kind of camera is this?",
"nl": "Wat voor soort camera is dit?"
},
"mappings": [
{
"if": {
"and": [
"camera:type=fixed"
]
},
"then": {
"en": "A fixed (non-moving) camera",
"nl": "Een vaste camera"
}
},
{
"if": {
"and": [
"camera:type=dome"
]
},
"then": {
"en": "A dome camera (which can turn)",
"nl": "Een dome (bolvormige camera die kan draaien)"
}
},
{
"if": {
"and": [
"camera:type=panning"
]
},
"then": {
"en": "A panning camera",
"nl": "Een camera die (met een motor) van links naar rechts kan draaien"
}
}
]
},
{
"#": "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view",
"question": {
"en": "In which geographical direction does this camera film?",
"nl": "Naar welke geografische richting filmt deze camera?"
},
"render": "Films to {camera:direction}",
"condition": {
"or": [
"camera:type!=dome",
{
"and": [
"camera:mount!=ceiling",
"camera:mount!=pole"
]
}
]
},
"freeform": {
"key": "camera:direction",
"type": "direction"
}
},
{
"#": "Operator",
"freeform": {
"key": "operator"
},
"question": {
"en": "Who operates this CCTV?",
"nl": "Wie beheert deze bewakingscamera?"
},
"render": {
"en": "Operated by {operator}",
"nl": "Beheer door {operator}"
}
},
{
"#": "Surveillance type: public, outdoor, indoor",
"question": {
"en": "What kind of surveillance is this camera",
"nl": "Wat soort bewaking wordt hier uitgevoerd?"
},
"mappings": [
{
"if": {
"and": [
"surveillance=public"
]
},
"then": {
"en": "A public area is surveilled, such as a street, a bridge, a square, a park, a train station, a public corridor or tunnel,...",
"nl": "Bewaking van de publieke ruilmte, dus een straat, een brug, een park, een plein, een stationsgebouw, een publiek toegankelijke gang of tunnel..."
}
},
{
"if": {
"and": [
"surveillance=outdoor"
]
},
"then": {
"en": "An outdoor, yet private area is surveilled (e.g. a parking lot, a fuel station, courtyard, entrance, private driveway, ...)",
"nl": "Een buitenruimte met privaat karakter (zoals een privé-oprit, een parking, tankstation, ...)"
}
},
{
"if": {
"and": [
"surveillance=indoor"
]
},
"then": {
"nl": "Een private binnenruimte wordt bewaakt, bv. een winkel, een parkeergarage, ...",
"en": "A private indoor area is surveilled, e.g. a shop, a private underground parking, ..."
}
}
]
},
{
"#": "Indoor camera? This isn't clear for 'public'-cameras",
"question": {
"en": "Is the public space surveilled by this camera an indoor or outdoor space?",
"nl": "Bevindt de bewaakte publieke ruimte camera zich binnen of buiten?"
},
"condition": {
"and": [
"surveillance:type=public"
]
},
"mappings": [
{
"if": "indoor=yes",
"then": {
"en": "This camera is located indoors",
"nl": "Deze camera bevindt zich binnen"
}
},
{
"if": "indoor=no",
"then": {
"en": "This camera is located outdoors",
"nl": "Deze camera bevindt zich buiten"
}
},
{
"if": "indoor=",
"then": {
"en": "This camera is probably located outdoors",
"nl": "Deze camera bevindt zich waarschijnlijk buiten"
},
"hideInAnswer": true
}
]
},
{
"#": "Level",
"question": {
"en": "On which level is this camera located?",
"nl": "Op welke verdieping bevindt deze camera zich?"
},
"freeform": {
"key": "level",
"type": "nat"
},
"condition": {
"or": [
"indoor=yes",
"surveillance:type=ye"
]
}
},
{
"#": "Surveillance:zone",
"question": {
"en": "What exactly is surveilled here?",
"nl": "Wat wordt hier precies bewaakt?"
},
"freeform": {
"key": "surveillance:zone"
},
"render": {
"en": " Surveills a {surveillance:zone}",
"nl": "Bewaakt een {surveillance:zone}"
},
"mappings": [
{
"if": {
"and": [
"surveillance:zone=parking"
]
},
"then": {
"en": "Surveills a parking",
"nl": "Bewaakt een parking"
}
},
{
"if": {
"and": [
"surveillance:zone=traffic"
]
},
"then": {
"en": "Surveills the traffic",
"nl": "Bewaakt het verkeer"
}
},
{
"if": {
"and": [
"surveillance:zone=entrance"
]
},
"then": {
"en": "Surveills an entrance",
"nl": "Bewaakt een ingang"
}
},
{
"if": {
"and": [
"surveillance:zone=corridor"
]
},
"then": {
"en": "Surveills a corridor",
"nl": "Bewaakt een gang"
}
},
{
"if": {
"and": [
"surveillance:zone=public_transport_platform"
]
},
"then": {
"en": "Surveills a public tranport platform",
"nl": "Bewaakt een perron of bushalte"
}
},
{
"if": {
"and": [
"surveillance:zone=shop"
]
},
"then": {
"en": "Surveills a shop",
"nl": "Bewaakt een winkel"
}
}
]
},
{
"#": "camera:mount",
"question": {
"en": "How is this camera placed?",
"nl": "Hoe is deze camera geplaatst?"
},
"freeform": {
"key": "camera:mount"
},
"mappings": [
{
"if": "camera:mount=wall",
"then": {
"en": "This camera is placed against a wall",
"nl": "Deze camera hangt aan een muur"
}
},
{
"if": "camera:mount=pole",
"then": {
"en": "This camera is placed one a pole",
"nl": "Deze camera staat op een paal"
}
},
{
"if": "camera:mount=ceiling",
"then": {
"en": "This camera is placed on the ceiling",
"nl": "Deze camera hangt aan het plafond"
}
}
]
}
],
"hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "./assets/themes/surveillance_cameras/logo.svg",
"mappings": [
{
"if": "camera:type=dome",
"then": "./assets/themes/surveillance_cameras/dome.svg"
},
{
"if": "_direction:leftright=right",
"then": "./assets/themes/surveillance_cameras/cam_right.svg"
},
{
"if": "_direction:leftright=left",
"then": "./assets/themes/surveillance_cameras/cam_left.svg"
}
]
},
"rotation": {
"render": "calc({camera:direction}deg + 90deg)",
"mappings": [
{
"if": "camera:type=dome",
"then": "0"
},
{
"if": "_direction:leftright=right",
"then": "calc({camera:direction}deg - 90deg)"
}
]
},
"width": {
"render": "8"
},
"iconSize": {
"mappings": [
{
"if": "camera:type=dome",
"then": "50,50,center"
},
{
"if": "_direction:leftright~*",
"then": "100,35,center"
}
],
"render": "50,50,center"
},
"color": {
"render": "#f00"
},
"presets": [
{
"tags": [
"man_made=surveillance",
"surveillance:type=camera"
],
"title": "Surveillance camera"
}
],
"wayHandling": 2
}

View file

@ -4,7 +4,7 @@
}, },
"osmlink": { "osmlink": {
"render": "<a href='https://openstreetmap.org/{id}' target='_blank'><img src='data:image/svg+xml;base64,PHN2ZyBjbGFzcz0nb3NtLWxvZ28nIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgaGVpZ2h0PSIxMDBweCIgd2lkdGg9IjEwMHB4IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA2NiA2NCI+CiAgICA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC44NDksIC02MSkiIGZpbGw9IiM3ZWJjNmYiPgogICAgICAgIDxwYXRoIGQ9Ik0wLjg0OSw2MSBMNi40MTQsNzUuNjA5IEwwLjg0OSw5MC4yMTcgTDYuNDE0LDEwNC44MjYgTDAuODQ5LDExOS40MzUgTDQuMjY2LDEyMC43MzkgTDIyLjgzMSwxMDIuMTgzIEwyNi4xNjIsMTAyLjY5NiBMMzAuMjA1LDk4LjY1MiBDMjcuODE5LDk1Ljg4OCAyNi4wMzMsOTIuNTkgMjUuMDU3LDg4Ljk0OCBMMjYuOTUzLDg3LjM5MSBDMjYuNjI3LDg1Ljg3OSAyNi40NDksODQuMzEzIDI2LjQ0OSw4Mi43MDQgQzI2LjQ0OSw3NC42NyAzMC43MzQsNjcuNjExIDM3LjEzNiw2My42OTYgTDMwLjA2Niw2MSBMMTUuNDU3LDY2LjU2NSBMMC44NDksNjEgeiIvPgogICAgICAgIDxwYXRoIGQ9Ik00OC43MSw2NC42MTcgQzQ4LjQwNiw2NC42MTcgNDguMTA1LDY0LjYyOSA0Ny44MDUsNjQuNjQzIEM0Ny41Miw2NC42NTcgNDcuMjM0LDY0LjY3NyA0Ni45NTMsNjQuNzA0IEM0Ni43MjYsNjQuNzI2IDQ2LjQ5OSw2NC43NTMgNDYuMjc1LDY0Ljc4MyBDNDYuMDM5LDY0LjgxNCA0NS44MTEsNjQuODQ3IDQ1LjU3OSw2NC44ODcgQzQ1LjUwNiw2NC45IDQ1LjQzNCw2NC45MTcgNDUuMzYyLDY0LjkzIEM0NS4yMTYsNjQuOTU4IDQ1LjA3Miw2NC45ODcgNDQuOTI3LDY1LjAxNyBDNDQuODEyLDY1LjA0MiA0NC42OTQsNjUuMDYgNDQuNTc5LDY1LjA4NyBDNDQuNDQyLDY1LjExOSA0NC4zMDcsNjUuMTU2IDQ0LjE3LDY1LjE5MSBDNDMuOTQzLDY1LjI1IDQzLjcxNiw2NS4zMTUgNDMuNDkyLDY1LjM4MyBDNDMuMzIzLDY1LjQzMyA0My4xNTUsNjUuNDg0IDQyLjk4OCw2NS41MzkgQzQyLjgxOSw2NS41OTUgNDIuNjUsNjUuNjUyIDQyLjQ4Myw2NS43MTMgQzQyLjQ3NSw2NS43MTYgNDIuNDY2LDY1LjcxOSA0Mi40NTcsNjUuNzIyIEMzNS44MTksNjguMTU4IDMxLjAyMiw3NC4zNjkgMzAuNjQ5LDgxLjc3NCBDMzAuNjMzLDgyLjA4MyAzMC42MjIsODIuMzkxIDMwLjYyMiw4Mi43MDQgQzMwLjYyMiw4My4wMTQgMzAuNjMxLDgzLjMyMSAzMC42NDksODMuNjI2IEMzMC42NDksODMuNjI5IDMwLjY0OCw4My42MzIgMzAuNjQ5LDgzLjYzNSBDMzAuNjYyLDgzLjg2MiAzMC42ODEsODQuMDg4IDMwLjcwMSw4NC4zMTMgQzMxLjQ2Niw5My4wMzcgMzguMzc3LDk5Ljk0OCA0Ny4xMDEsMTAwLjcxMyBDNDcuMzI2LDEwMC43MzMgNDcuNTUyLDEwMC43NTQgNDcuNzc5LDEwMC43NjUgQzQ3Ljc4MiwxMDAuNzY1IDQ3Ljc4NSwxMDAuNzY1IDQ3Ljc4OCwxMDAuNzY1IEM0OC4wOTMsMTAwLjc4MyA0OC4zOTksMTAwLjc5MSA0OC43MDksMTAwLjc5MSBDNTMuNjM5LDEwMC43OTEgNTguMDk2LDk4LjgzMyA2MS4zNTMsOTUuNjUyIEM2MS41MzIsOTUuNDc3IDYxLjcxMiw5NS4zMDQgNjEuODgzLDk1LjEyMiBDNjEuOTEzLDk1LjA5IDYxLjk0MSw5NS4wNTggNjEuOTcsOTUuMDI2IEM2MS45OCw5NS4wMTUgNjEuOTg3LDk1LjAwMiA2MS45OTYsOTQuOTkxIEM2Mi4xMzIsOTQuODQ1IDYyLjI2Niw5NC42OTggNjIuMzk2LDk0LjU0OCBDNjIuNDQ5LDk0LjQ4NyA2Mi41MDEsOTQuNDI2IDYyLjU1Myw5NC4zNjUgQzYyLjU5NCw5NC4zMTYgNjIuNjM0LDk0LjI2NyA2Mi42NzUsOTQuMjE3IEM2Mi44MjEsOTQuMDQgNjIuOTYxLDkzLjg2MSA2My4xMDEsOTMuNjc4IEM2My4yNzksOTMuNDQ0IDYzLjQ1Niw5My4xOTkgNjMuNjIyLDkyLjk1NiBDNjMuOTU2LDkyLjQ3MSA2NC4yNjcsOTEuOTcgNjQuNTUzLDkxLjQ1MiBDNjQuNjYxLDkxLjI1NyA2NC43NTcsOTEuMDYgNjQuODU3LDkwLjg2MSBDNjQuODksOTAuNzk2IDY0LjkzLDkwLjczNSA2NC45NjIsOTAuNjcgQzY0Ljk4LDkwLjYzMyA2NC45OTYsOTAuNTk0IDY1LjAxNCw5MC41NTYgQzY1LjEyNSw5MC4zMjQgNjUuMjM0LDkwLjA5IDY1LjMzNiw4OS44NTIgQzY1LjM0OSw4OS44MiA2NS4zNjUsODkuNzg5IDY1LjM3OSw4OS43NTYgQzY1LjQ4LDg5LjUxNyA2NS41NzUsODkuMjcxIDY1LjY2Niw4OS4wMjYgQzY1LjY3OCw4OC45OTQgNjUuNjg5LDg4Ljk2MiA2NS43MDEsODguOTMgQzY1Ljc5Miw4OC42NzkgNjUuODgxLDg4LjQzIDY1Ljk2Miw4OC4xNzQgQzY1Ljk3LDg4LjE0OCA2NS45OCw4OC4xMjIgNjUuOTg4LDg4LjA5NiBDNjYuMDY5LDg3LjgzMiA2Ni4xNDQsODcuNTY0IDY2LjIxNCw4Ny4yOTYgQzY2LjIxOSw4Ny4yNzUgNjYuMjI2LDg3LjI1NSA2Ni4yMzEsODcuMjM1IEM2Ni4zMDEsODYuOTYyIDY2LjM2NSw4Ni42ODYgNjYuNDIzLDg2LjQwOSBDNjYuNDI2LDg2LjM5MSA2Ni40MjgsODYuMzc0IDY2LjQzMSw4Ni4zNTYgQzY2LjQ0NSw4Ni4yOTEgNjYuNDUzLDg2LjIyMyA2Ni40NjYsODYuMTU2IEM2Ni41MTEsODUuOTI1IDY2LjU1Miw4NS42OTUgNjYuNTg4LDg1LjQ2MSBDNjYuNjMyLDg1LjE2OSA2Ni42NzEsODQuODc4IDY2LjcwMSw4NC41ODMgQzY2LjcwMSw4NC41NzQgNjYuNzAxLDg0LjU2NSA2Ni43MDEsODQuNTU2IEM2Ni43MzEsODQuMjU4IDY2Ljc1NSw4My45NTUgNjYuNzcsODMuNjUyIEM2Ni43Nyw4My42NDYgNjYuNzcsODMuNjQxIDY2Ljc3LDgzLjYzNSBDNjYuNzg2LDgzLjMyNiA2Ni43OTcsODMuMDE3IDY2Ljc5Nyw4Mi43MDQgQzY2Ljc5Nyw3Mi42OSA1OC43MjMsNjQuNjE3IDQ4LjcxLDY0LjYxNyB6Ii8+CiAgICAgICAgPHBhdGggZD0iTTYyLjkzNiw5OS44MDkgQzU5LjA3NCwxMDMuMDI4IDU0LjExNSwxMDQuOTY1IDQ4LjcxLDEwNC45NjUgQzQ3LjEwMSwxMDQuOTY1IDQ1LjUzNSwxMDQuNzg3IDQ0LjAyMywxMDQuNDYxIEw0Mi40NjYsMTA2LjM1NyBDMzkuMDA3LDEwNS40MyAzNS44NTUsMTAzLjc4MSAzMy4xNzksMTAxLjU3NCBMMjguOTk2LDEwNS43NjUgTDI5LjUxLDEwOC44NjEgTDEzLjk1MywxMjQuNDI2IEwxNS40NTcsMTI1IEwzMC4wNjYsMTE5LjQzNSBMNDQuNjc1LDEyNSBMNTkuMjgzLDExOS40MzUgTDY0Ljg0OSwxMDQuODI2IEw2Mi45MzYsOTkuODA5IHoiLz4KICAgIDwvZz4KPC9zdmc+'/></a>", "render": "<a href='https://openstreetmap.org/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'/></a>",
"mappings":[{ "mappings":[{
"if": "id~=-", "if": "id~=-",
"then": "<span class='alert'>Uploading...</alert>" "then": "<span class='alert'>Uploading...</alert>"

View file

@ -1,55 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <svg
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="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" id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)" version="1.1"
sodipodi:docname="crosshair.svg"> viewBox="0 0 26.458333 26.458334"
height="100"
width="100">
<defs <defs
id="defs2" /> id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="12.898245"
inkscape:cy="23.072799"
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="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 <metadata
id="metadata5"> id="metadata5">
<rdf:RDF> <rdf:RDF>
@ -58,46 +20,40 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title /> <dc:title></dc:title>
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
<g <g
inkscape:label="Layer 1" transform="translate(0,-270.54165)"
inkscape:groupmode="layer" id="layer1">
id="layer1"
transform="translate(0,-270.54165)">
<circle <circle
style="fill:none;fill-opacity:1;stroke:#555555;stroke-width:2.64583335;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529" r="8.8715391"
id="path815" cy="283.77081"
cx="13.16302" cx="13.16302"
cy="283.77081" id="path815"
r="8.8715391" /> style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:2.64583335;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529" />
<path <path
style="fill:none;stroke:#555555;stroke-width:2.09723878;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529"
d="M 3.2841366,283.77082 H 1.0418969"
id="path817" id="path817"
inkscape:connector-curvature="0" /> d="M 3.2841366,283.77082 H 1.0418969"
style="fill:none;stroke:#000000;stroke-width:2.09723878;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529" />
<path <path
style="fill:none;stroke:#555555;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529"
d="M 25.405696,283.77082 H 23.286471"
id="path817-3" id="path817-3"
inkscape:connector-curvature="0" /> d="M 25.405696,283.77082 H 23.286471"
style="fill:none;stroke:#000000;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529" />
<path <path
style="fill:none;stroke:#555555;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529"
d="m 13.229167,295.9489 v -2.11763"
id="path817-3-6" id="path817-3-6"
inkscape:connector-curvature="0" /> d="m 13.229167,295.9489 v -2.11763"
style="fill:none;stroke:#000000;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529" />
<path <path
style="fill:none;stroke:#555555;stroke-width:2.11666668;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529"
d="m 13.229167,275.05759 v -3.44507"
id="path817-3-6-7" id="path817-3-6-7"
inkscape:connector-curvature="0" /> d="m 13.229167,275.05759 v -3.44507"
style="fill:none;stroke:#000000;stroke-width:2.11666668;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529" />
<circle <circle
style="fill:#555555;fill-opacity:0.99004978;stroke:none;stroke-width:2.81138086;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" r="3.4070117"
id="path866"
cx="13.229166"
cy="283.77081" cy="283.77081"
r="3.4070117" /> cx="13.229166"
id="path866"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.81138086;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -6,11 +6,48 @@
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100" width="100"
height="100" height="100"
viewBox="0 0 100 100" viewBox="0 0 100 100"
version="1.1" version="1.1"
id="svg8"> id="svg8"
sodipodi:docname="direction_gradient.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<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="namedview10"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="9.44"
inkscape:cx="69.372244"
inkscape:cy="85.073455"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8">
<sodipodi:guide
position="50,117.79661"
orientation="1,0"
id="guide819"
inkscape:locked="false" />
<sodipodi:guide
position="57.627119,50"
orientation="0,1"
id="guide821"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata <metadata
id="metadata8"> id="metadata8">
<rdf:RDF> <rdf:RDF>
@ -19,7 +56,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title> <dc:title />
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@ -38,7 +75,7 @@
</linearGradient> </linearGradient>
<radialGradient <radialGradient
gradientUnits="userSpaceOnUse" gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.5439431,-0.01852438,0.02075364,1.7297431,-28.198837,-42.329969)" gradientTransform="matrix(1.5439431,-0.01852438,0.02075364,1.7297431,-27.986574,-42.187244)"
r="28.883806" r="28.883806"
fy="53.828533" fy="53.828533"
fx="49.787739" fx="49.787739"
@ -49,6 +86,7 @@
</defs> </defs>
<path <path
style="fill:url(#radialGradient828);fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:url(#radialGradient828);fill-opacity:1;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 49.787737,49.857275 20.830626,9.2566092 C 35.979158,-2.144159 60.514289,-3.8195259 78.598237,9.0063685 Z" d="M 50,50 21.042889,9.3993342 C 36.191421,-2.001434 60.726552,-3.6768009 78.8105,9.1490935 Z"
id="path821" /> id="path821"
inkscape:connector-curvature="0" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -7,25 +7,12 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="300"
height="300"
version="1.1"
id="svg6" id="svg6"
version="1.1"
height="210"
width="600"
sodipodi:docname="cam.svg" sodipodi:docname="cam.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"> inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview <sodipodi:namedview
pagecolor="#ffffff" pagecolor="#ffffff"
bordercolor="#666666" bordercolor="#666666"
@ -37,19 +24,40 @@
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:window-width="1920" inkscape:window-width="1920"
inkscape:window-height="1001" inkscape:window-height="1001"
id="namedview8" id="namedview6"
showgrid="false" showgrid="false"
inkscape:zoom="4.4500586" showguides="true"
inkscape:cx="52.470633" inkscape:guide-bbox="true"
inkscape:cy="172.70315" inkscape:zoom="0.55625733"
inkscape:cx="680.78346"
inkscape:cy="482.50413"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="svg6" /> inkscape:current-layer="svg6">
<sodipodi:guide
position="192.35701,251.68207"
orientation="1,0"
id="guide816"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata12">
<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="defs10" />
<path <path
d="m 19.550568,165.17983 25.64048,-7.77529 37.583972,53 -44.404278,15.19092 z M 27.853974,129.44943 251,66 c 5.83831,-1.483989 13.98665,-0.576204 16.78652,10.077906 0,0 13.16723,59.102364 19.90559,86.841004 2.37442,9.77433 -0.21672,13.95095 -6.93927,15.75524 L 103,230 Z" style="fill:#000000;stroke:#ffffff;stroke-width:17.40477371;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4" id="path4"
inkscape:connector-curvature="0" d="m 275.84577,72.939087 31.07239,-1.014243 26.20685,70.688356 -54.3295,3.69054 z m 20.0366,-37.552344 269.15255,-4.09941 c 6.98913,0.09009 15.84901,3.554569 15.7875,16.336335 0,0 -2.99159,70.195112 -3.76963,103.307682 -0.27414,11.66795 -4.43254,15.57088 -12.5089,15.57422 l -214.63586,4.14367 z"
style="fill:#000000;stroke:#ffffff;stroke-width:15;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" inkscape:connector-curvature="0" />
sodipodi:nodetypes="cccccccssccc" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,68 @@
<?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"
id="svg6"
version="1.1"
height="210"
width="600"
sodipodi:docname="cam_right.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<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"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="1.5733333"
inkscape:cx="159.31"
inkscape:cy="209.94521"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg6">
<sodipodi:guide
position="490.78006,256.1764"
orientation="1,0"
id="guide816"
inkscape:locked="false" />
<sodipodi:guide
position="-154.49235,105.0548"
orientation="0,1"
id="guide817"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata12">
<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>
<defs
id="defs10" />
<path
style="fill:#000000;stroke:#ffffff;stroke-width:14.99999809;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4"
d="m 320.67971,63.887724 -31.22595,-0.646766 -25.27602,71.641802 54.62643,3.06524 z M 299.99723,26.240468 29.583962,25.366424 c -7.018953,0.175611 -15.866995,3.778632 -15.615761,16.674621 0,0 4.045287,70.790225 5.317545,104.191185 0.448302,11.76958 4.683081,15.65722 12.795492,15.56269 l 215.654182,1.57947 z"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,78 @@
<?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:xlink="http://www.w3.org/1999/xlink"
id="svg8"
version="1.1"
viewBox="0 0 100 100"
height="100"
width="100">
<metadata
id="metadata8">
<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="defs6">
<linearGradient
id="linearGradient823">
<stop
id="stop819"
offset="0"
style="stop-color:#55ff55;stop-opacity:1;" />
<stop
id="stop821"
offset="1"
style="stop-color:#55ff55;stop-opacity:0;" />
</linearGradient>
<linearGradient
id="linearGradient820">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="innercolor" />
<stop
style="stop-color:#000000;stop-opacity:0"
offset="1"
id="outercolor" />
</linearGradient>
<radialGradient
xlink:href="#linearGradient820"
id="radialGradient828"
cx="49.787739"
cy="53.828533"
fx="49.787739"
fy="53.828533"
r="28.883806"
gradientTransform="matrix(1.5439431,-0.01852438,0.02075364,1.7297431,-28.198837,-42.329969)"
gradientUnits="userSpaceOnUse" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.99367722,0,0.31814846)"
r="50.261864"
fy="50.317799"
fx="50.211864"
cy="50.317799"
cx="50.211864"
id="radialGradient825"
xlink:href="#linearGradient823" />
</defs>
<ellipse
ry="49.89407"
rx="50.211864"
cy="50.317799"
cx="50.211864"
id="path817"
style="fill:url(#radialGradient825);fill-opacity:1;stroke:#0f0000;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -7,8 +7,8 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="300" width="100"
height="300" height="100"
version="1.1" version="1.1"
id="svg6" id="svg6"
sodipodi:docname="dome.svg" sodipodi:docname="dome.svg"
@ -21,6 +21,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@ -39,29 +40,42 @@
inkscape:window-height="1001" inkscape:window-height="1001"
id="namedview8" id="namedview8"
showgrid="false" showgrid="false"
inkscape:zoom="1.5733334" inkscape:zoom="11.313708"
inkscape:cx="-20.982269" inkscape:cx="52.167677"
inkscape:cy="188.2981" inkscape:cy="58.44587"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="svg6" /> inkscape:current-layer="svg6"
showguides="true"
inkscape:guide-bbox="true">
<sodipodi:guide
position="50.25,94.25"
orientation="1,0"
id="guide819"
inkscape:locked="false" />
<sodipodi:guide
position="-9.9375,50"
orientation="0,1"
id="guide821"
inkscape:locked="false" />
</sodipodi:namedview>
<path <path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:4.36474609;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 34.759205,66.019166 H 262.93718 c 37.50409,0.111509 38.67272,47.104634 0,46.615174 H 34.759205 c -33.95631907,0.10039 -33.5365026,-46.998069 0,-46.615174 z" d="m 11.439881,11.609325 h 76.341284 c 12.547715,0.03599 12.938695,15.219042 0,15.060906 H 11.439881 c -11.36071647,0.03243 -11.220258,-15.184617 0,-15.060906 z"
id="path818" id="path818"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" /> sodipodi:nodetypes="ccccc" />
<path <path
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:15;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:4.36474609;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 49.750453,122.23061 249.19481,121.8402 C 248.9489,280.24546 49.140118,276.05333 49.750453,122.23061 Z" d="m 17.002109,29.775376 66.727903,0.0063 c -0.08223,51.179228 -66.932094,49.692075 -66.727903,-0.0063 z"
id="path823" id="path823"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" /> sodipodi:nodetypes="ccc" />
<g <g
id="g848" id="g848"
transform="matrix(1.4204816,0,0,1.4204816,-61.951413,-40.990558)" transform="matrix(0.47524917,0,0,0.45894372,-20.936465,-23.265017)"
style="stroke-width:0.70398653"> style="stroke-width:1.86916912">
<ellipse <ellipse
ry="23.81991" ry="23.81991"
rx="24.494061" rx="24.494061"

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -40,7 +40,7 @@
id="namedview8" id="namedview8"
showgrid="false" showgrid="false"
inkscape:zoom="1.1125147" inkscape:zoom="1.1125147"
inkscape:cx="-139.39327" inkscape:cx="-288.60478"
inkscape:cy="92.396852" inkscape:cy="92.396852"
inkscape:window-x="0" inkscape:window-x="0"
inkscape:window-y="0" inkscape:window-y="0"
@ -49,11 +49,12 @@
<circle <circle
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path812" id="path812"
cx="150.55981" cx="-150.55981"
cy="149.44019" cy="149.44019"
r="148.76208" /> r="148.76208"
transform="scale(-1,1)" />
<path <path
d="m 40.704254,162.40461 21.579577,-6.49818 31.631474,44.29458 -37.37159,12.69576 z M 47.692578,132.54304 235.49705,79.515388 c 4.91364,-1.240239 11.77146,-0.481561 14.12789,8.422577 0,0 11.08182,49.394605 16.75297,72.577085 1.99836,8.16887 -0.18239,11.65946 -5.84024,13.16739 l -149.60059,42.89541 z" d="m 260.41537,162.40461 -21.57957,-6.49818 -31.63148,44.29458 37.37159,12.69576 z M 253.42705,132.54304 65.622579,79.515388 c -4.91364,-1.240239 -11.77146,-0.481561 -14.12789,8.422577 0,0 -11.08182,49.394605 -16.75297,72.577085 -1.99836,8.16887 0.18239,11.65946 5.84024,13.16739 l 149.600591,42.89541 z"
id="path4" id="path4"
inkscape:connector-curvature="0" inkscape:connector-curvature="0"
style="fill:#000000;stroke:#00ff00;stroke-width:15;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" style="fill:#000000;stroke:#00ff00;stroke-width:15;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -28,353 +28,7 @@
"defaultBackgroundId": "Stadia.AlidadeSmoothDark", "defaultBackgroundId": "Stadia.AlidadeSmoothDark",
"layers": [ "layers": [
"direction", "direction",
{ "surveillance_cameras"
"id": "cameras",
"name": {
"en": "Surveillance camera's",
"nl": "Bewakingscamera's"
},
"minzoom": 12,
"overpassTags": {
"and": [
"man_made=surveillance",
{
"or": [
"surveillance:type=camera",
"surveillance:type=ALPR",
"surveillance:type=ANPR"
]
}
]
},
"title": {
"render": {
"en": "Surveillance Camera",
"nl": "Bewakingscamera"
}
},
"description": {},
"tagRenderings": [
"images",
{
"#": "Camera type: fixed; panning; dome",
"question": {
"en": "What kind of camera is this?",
"nl": "Wat voor soort camera is dit?"
},
"mappings": [
{
"if": {
"and": [
"camera:type=fixed"
]
},
"then": {
"en": "A fixed (non-moving) camera",
"nl": "Een vaste camera"
}
},
{
"if": {
"and": [
"camera:type=dome"
]
},
"then": {
"en": "A dome camera (which can turn)",
"nl": "Een dome (bolvormige camera die kan draaien)"
}
},
{
"if": {
"and": [
"camera:type=panning"
]
},
"then": {
"en": "A panning camera",
"nl": "Een camera die (met een motor) van links naar rechts kan draaien"
}
}
]
},
{
"#": "direction. We don't ask this for a dome on a pole or ceiling as it has a 360° view",
"question": {
"en": "In which geographical direction does this camera film?",
"nl": "Naar welke geografische richting filmt deze camera?"
},
"render": "Films to {camera:direction}",
"condition": {
"not": {
"and": [
"camera:type=dome",
{
"or": [
"camera:mount=ceiling",
"camera:mount=pole"
]
}
]
}
},
"freeform": {
"key": "camera:direction",
"type": "direction"
}
},
{
"#": "Operator",
"freeform": {
"key": "operator"
},
"question": {
"en": "Who operates this CCTV?",
"nl": "Wie beheert deze bewakingscamera?"
},
"render": {
"en": "Operated by {operator}",
"nl": "Beheer door {operator}"
}
},
{
"#": "Surveillance type: public, outdoor, indoor",
"question": {
"en": "What kind of surveillance is this camera",
"nl": "Wat soort bewaking wordt hier uitgevoerd?"
},
"mappings": [
{
"if": {
"and": [
"surveillance=public"
]
},
"then": {
"en": "A public area is surveilled, such as a street, a bridge, a square, a park, a train station, a public corridor or tunnel,...",
"nl": "Bewaking van de publieke ruilmte, dus een straat, een brug, een park, een plein, een stationsgebouw, een publiek toegankelijke gang of tunnel..."
}
},
{
"if": {
"and": [
"surveillance=outdoor"
]
},
"then": {
"en": "An outdoor, yet private area is surveilled (e.g. a parking lot, a fuel station, courtyard, entrance, private driveway, ...)",
"nl": "Een buitenruimte met privaat karakter (zoals een privé-oprit, een parking, tankstation, ...)"
}
},
{
"if": {
"and": [
"surveillance=indoor"
]
},
"then": {
"nl": "Een private binnenruimte wordt bewaakt, bv. een winkel, een parkeergarage, ...",
"en": "A private indoor area is surveilled, e.g. a shop, a private underground parking, ..."
}
}
]
},
{
"#": "Indoor camera? This isn't clear for 'public'-cameras",
"question": {
"en": "Is the public space surveilled by this camera an indoor or outdoor space?",
"nl": "Bevindt de bewaakte publieke ruimte camera zich binnen of buiten?"
},
"condition": {
"and": [
"surveillance:type=public"
]
},
"mappings": [
{
"if": "indoor=yes",
"then": {
"en": "This camera is located indoors",
"nl": "Deze camera bevindt zich binnen"
}
},
{
"if": "indoor=no",
"then": {
"en": "This camera is located outdoors",
"nl": "Deze camera bevindt zich buiten"
}
},
{
"if": "indoor=",
"then": {
"en": "This camera is probably located outdoors",
"nl": "Deze camera bevindt zich waarschijnlijk buiten"
},
"hideInAnswer": true
}
]
},
{
"#": "Level",
"question": {
"en": "On which level is this camera located?",
"nl": "Op welke verdieping bevindt deze camera zich?"
},
"freeform": {
"key": "level",
"type": "nat"
},
"condition": {
"or": [
"indoor=yes",
"surveillance:type=ye"
]
}
},
{
"#": "Surveillance:zone",
"question": {
"en": "What exactly is surveilled here?",
"nl": "Wat wordt hier precies bewaakt?"
},
"freeform": {
"key": "surveillance:zone"
},
"render": {
"en": " Surveills a {surveillance:zone}",
"nl": "Bewaakt een {surveillance:zone}"
},
"mappings": [
{
"if": {
"and": [
"surveillance:zone=parking"
]
},
"then": {
"en": "Surveills a parking",
"nl": "Bewaakt een parking"
}
},
{
"if": {
"and": [
"surveillance:zone=traffic"
]
},
"then": {
"en": "Surveills the traffic",
"nl": "Bewaakt het verkeer"
}
},
{
"if": {
"and": [
"surveillance:zone=entrance"
]
},
"then": {
"en": "Surveills an entrance",
"nl": "Bewaakt een ingang"
}
},
{
"if": {
"and": [
"surveillance:zone=corridor"
]
},
"then": {
"en": "Surveills a corridor",
"nl": "Bewaakt een gang"
}
},
{
"if": {
"and": [
"surveillance:zone=public_transport_platform"
]
},
"then": {
"en": "Surveills a public tranport platform",
"nl": "Bewaakt een perron of bushalte"
}
},
{
"if": {
"and": [
"surveillance:zone=shop"
]
},
"then": {
"en": "Surveills a shop",
"nl": "Bewaakt een winkel"
}
}
]
},
{
"#": "camera:mount",
"question": {
"en": "How is this camera placed?",
"nl": "Hoe is deze camera geplaatst?"
},
"freeform": {
"key": "camera:mount"
},
"mappings": [
{
"if": "camera:mount=wall",
"then": {
"en": "This camera is placed against a wall",
"nl": "Deze camera hangt aan een muur"
}
},
{
"if": "camera:mount=pole",
"then": {
"en": "This camera is placed one a pole",
"nl": "Deze camera staat op een paal"
}
},
{
"if": "camera:mount=ceiling",
"then": {
"en": "This camera is placed on the ceiling",
"nl": "Deze camera hangt aan het plafond"
}
}
]
}
],
"hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "./assets/themes/surveillance_cameras/cam.svg",
"mappings": [
{
"if": "camera:type=dome",
"then": "./assets/themes/surveillance_cameras/dome.svg"
}
]
},
"width": {
"render": "8"
},
"iconSize": {
"render": "50,50,center"
},
"color": {
"render": "#f00"
},
"presets": [
{
"tags": ["man_made=surveillance","surveillance:type=camera"],
"title": "Surveillance camera"
}
],
"wayHandling": 2
}
], ],
"roamingRenderings": [] "roamingRenderings": []
} }

View file

@ -173,6 +173,10 @@ a {
pointer-events: all; pointer-events: all;
} }
.unclickable {
pointer-events: none !important;
}
.page-split { .page-split {
display: flex; display: flex;
height: 100%; height: 100%;
@ -415,6 +419,7 @@ a {
border: unset !important; border: unset !important;
} }
/****** ShareScreen *****/ /****** ShareScreen *****/
.literal-code { .literal-code {

View file

@ -21,7 +21,7 @@
"generate:layouts": "ts-node scripts/createLayouts.ts", "generate:layouts": "ts-node scripts/createLayouts.ts",
"optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'", "optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
"generate": "npm run generate:images && npm run generate:translations && npm run generate:layouts && npm run generate:editor-layer-index", "generate": "npm run generate:images && npm run generate:translations && npm run generate:layouts && npm run generate:editor-layer-index",
"build": "rm -rf dist/ npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*", "build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*",
"prepare-deploy": "npm run generate && npm run build && rm -rf .cache", "prepare-deploy": "npm run generate && npm run build && rm -rf .cache",
"deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", "deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"deploy:production": "npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean", "deploy:production": "npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",

View file

@ -100,7 +100,7 @@ const alreadyWritten = []
function createIcon(iconPath: string, size: number, layout: LayoutConfig) { function createIcon(iconPath: string, size: number, layout: LayoutConfig) {
let name = iconPath.split(".").slice(0, -1).join("."); let name = iconPath.split(".").slice(0, -1).join(".");
if (name.startsWith("../")) { if (name.startsWith("./")) {
name = name.substr(2) name = name.substr(2)
} }
const newname = `${name}${size}.png` const newname = `${name}${size}.png`
@ -151,7 +151,7 @@ function createManifest(layout: LayoutConfig, relativePath: string) {
let path = layout.icon; let path = layout.icon;
if (layout.icon.startsWith("<")) { if (layout.icon.startsWith("<")) {
// THis is already the svg // THis is already the svg
path = "../assets/generated/" + layout.id + "_logo.svg" path = "./assets/generated/" + layout.id + "_logo.svg"
writeFileSync(path, layout.icon) writeFileSync(path, layout.icon)
} }
@ -212,19 +212,19 @@ function createLandingPage(layout: LayoutConfig) {
} }
const og = ` const og = `
<meta property="og:image" content="${ogImage ?? '../assets/svg/add.svg'}"> <meta property="og:image" content="${ogImage ?? './assets/svg/add.svg'}">
<meta property="og:title" content="${ogTitle}"> <meta property="og:title" content="${ogTitle}">
<meta property="og:description" content="${ogDescr}">` <meta property="og:description" content="${ogDescr}">`
let icon = layout.icon; let icon = layout.icon;
if (icon.startsWith("<?xml") || icon.startsWith("<svg")) { if (icon.startsWith("<?xml") || icon.startsWith("<svg")) {
// This already is an svg // This already is an svg
icon = `../assets/generated/${layout.id}_icon.svg` icon = `./assets/generated/${layout.id}_icon.svg`
writeFileSync(icon, layout.icon); writeFileSync(icon, layout.icon);
} }
let output = template let output = template
.replace(`../manifest.manifest`, `../${enc(layout.id)}.webmanifest`) .replace(`./manifest.manifest`, `./${enc(layout.id)}.webmanifest`)
.replace("<!-- $$$OG-META -->", og) .replace("<!-- $$$OG-META -->", og)
.replace(/<title>.+?<\/title>/, `<title>${ogTitle}</title>`) .replace(/<title>.+?<\/title>/, `<title>${ogTitle}</title>`)
.replace("Loading MapComplete, hang on...", `Loading MapComplete theme <i>${ogTitle}</i>...`) .replace("Loading MapComplete, hang on...", `Loading MapComplete theme <i>${ogTitle}</i>...`)
@ -243,6 +243,11 @@ function createLandingPage(layout: LayoutConfig) {
return output; return output;
} }
const generatedDir = "./assets/generated";
if (! existsSync(generatedDir)) {
mkdirSync(generatedDir)
}
const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap"] const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap"]
const all = AllKnownLayouts.allSets; const all = AllKnownLayouts.allSets;
@ -251,10 +256,7 @@ let wikiPage = "{|class=\"wikitable sortable\"\n" +
"|-"; "|-";
const generatedDir = "../assets/generated";
if (! existsSync(generatedDir)) {
mkdirSync(generatedDir)
}
for (const layoutName in all) { for (const layoutName in all) {
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) { if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {