Bicycle Master Plan is a tool / web app for displaying various bicycle infrastructure related data on a map. Actually, you can use any OpenStreetMap / custom data on a map, not just bicycle-related data. Extensive visual customization is possible by automatical conversion of OSM keys and values to CSS classes.
It supports the following sources of data:
Built with:
https://mapa.cyklokoalicia.sk/bratislava/public/
composer install
to download dependenciesphp artisan migrate
to setup databasepublic/.htaccess
file permissions, if necessarystorage/app/
permissions, if necessary (755 for writing)storage/app/public/uploads/
directory (755), if an editable layer is enabledstorage/app/osm/
directory (755), if OSM layer download is enabled (see below)public/storage/
(TARGET) to storage/app/public/uploads/
(SOURCE), if an editable layer is enabled (see https://laravel.com/docs/7.x/filesystem#the-public-disk)config/map.php
layers
:
0
in config filetype
= path
, marker
, combined
name
= name of a layer (can contain HTML tags)class
= CSS class to be used to mark up layer items (markers / paths)icon
= layer item icon (markers only) will be created from either name
or filename
in databasefile
= OSM JSON file containing layer content (markers or paths/ways downloaded from OSM)cluster
= true
for layers to group/cluster items/markerseditable
= true
for the user editable layer (user submitted items require admin approval, see below)types
= array a layer can contain multiple types of items such as different sets of markers etc.osm_server
= https://lz4.overpass-api.de/api/interpreter
(use any OSM server)osm_data
= array of map layers with file
parameter:
file
= filename to save the filedata
= overpass query to download OSM data, e.g. [out:json]; (relation[network=lcn]({{bbox}}); ); out body; >; out skel qt;
, see https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_API_by_Exampleadmins
= array of admin emails, e.g. ['someone@example.com', 'other@example.com']approved
column to 1
in database. If user marked an item as outdated
(1
in database), set deleted
to 1
in database to hide it from a map.config/bikeshare.example.php
for details on how to enable data download (public bikeshare API endpoint required)config/google.example.php
file on how to configure it (you will need to create a project with service access with client_id
and JSON keyfile
at https://console.developers.google.com)config/services.php
and add the following lines:
'google' => [
'client_id' => 'your_client_id',
'client_secret' => 'your_client_secret',
'redirect' => 'callback URL', // callback URL for OAuth authentication, e.g. http://example.com/login/google/callback
],
All standard map tiles providers are supported.
Open public/css/main.css
to customize layer markers or styles of paths etc. SVG properties (fill
, stroke
etc.) need to be used for styling paths/OSM ways, see https://css-tricks.com/svg-properties-and-css/.
Example of path classes created from OpenStreetMap data (bicycle lane):
class="path cycleway-left-lane cycleway-right-shared_lane foot-use_sidepath highway-residential lit-yes maxspeed-30 name-dunajska name-hu-dunautca surface-asphalt trolley_wire-yes"
Example of marker classes created from OpenStreetMap data (bicycle parking):
class="marker access-private amenity-bicycle_parking covered-yes surveillance-yes parking"
Any combinations of keys / values can be easily styled for your purposes by using standardized CSS.
Setup cron to call refresh URLs daily (or other interval), e.g.:
15 0 * * * /usr/bin/curl --silent https://example.com/public/refresh/osm >/dev/null 2>&1
Update endpoints are:
/refresh/osm
/refresh/bikeshare
/refresh/googlesheet
/refresh/feed
public/photos
directory (create this directory, if it does not exist)php artisan db:seed --class=PhotosSeeder
config/map.php
(enabling clustering will help with large number of photos) and adding this code to layers
:
1 => [
'type' => 'marker',
'name' => 'Your photos',
'class' => 'photo',
'icon' => 'filename',
'cluster' => true,
'options' => [
'disableClusteringAtZoom' => 17,
],
],
config/map.php
and add a layer (change number 5
to suit your purposes) to the layers
:
5 => [
'type' => 'path',
'name' => 'Cycling paths<br><span class="cycleway-lane">━━━</span> Segregated<br><span class="cycleway-shared_lane">━━━</span> Shared<br><span class="lcn-provisional">• • • •</span> Recommended<br><span class="highway-pedestrian">━━━</span> Pedestrianized<br><span class="mtb-scale">━━━</span> For mountain bikes',
'class' => 'ways',
'file' => 'ways.json',
],
config/map.php
. Change network
operator name to your city's one (e.g. Slovnaft BAjk
for Bratislava):
// OSM data to fetch
'osm_server' => 'https://lz4.overpass-api.de/api/interpreter',
'osm_data' => [
[
'file' => 'ways.json',
'data' => '[out:json]; (way[cycleway]({{bbox}}); way["cycleway:left"]({{bbox}}); way["cycleway:right"]({{bbox}}); way[highway=pedestrian]({{bbox}}); way[highway=cycleway]({{bbox}}); way[bicycle=yes]({{bbox}}); way[bicycle=official]({{bbox}}); way[lcn]({{bbox}}); way[bicycle=designated]({{bbox}}); ); out body; >; out skel qt;',
],
[
'file' => 'bikeshare-sb.json',
'data' => '[out:json]; (node[network="Slovnaft BAjk"]({{bbox}}); ); out body; >; out skel qt;',
],
],
config/map.php
and add a layer (change number 2
to suit your purposes) to the layers
:
2 => [
'type' => 'marker',
'name' => 'Bicycle parking<br><span class="parking"></span> <span class="parking bicycle_parking-rack"></span> <span class="parking bicycle_parking-shed"></span> Safe<br><span class="parking bicycle_parking-anchors"></span> Unsuitable<br><span class="amenity-bicycle_repair_station"></span> Public pump and tools',
'class' => 'parking',
'file' => 'parking.json',
],
config/map.php
:
'osm_server' => 'https://lz4.overpass-api.de/api/interpreter',
'osm_data' => [
[
'file' => 'parking.json',
'data' => '[out:json]; (node[amenity="bicycle_parking"]({{bbox}}); node["amenity"="bicycle_repair_station"]({{bbox}}); ); out body; >; out skel qt;',
],
],