Move around READMEs

pull/147/head
Candid Dauth 2021-04-10 01:45:20 +02:00
rodzic df2bb6352c
commit 20b87e2f46
22 zmienionych plików z 823 dodań i 972 usunięć

Wyświetl plik

@ -1,53 +1,30 @@
[**FacilMap**](https://facilmap.org/) is an online map that aims to bring together many useful functions in a usable and pretty way onto an
open-source map based on [OpenStreetMap](https://openstreetmap.org/). Features include:
[FacilMap](https://facilmap.org/) is a privacy-friendly, open-source versatile online map that combines different services based on OpenStreetMap and makes it easy to find places, plan routes and create custom maps full of markers, lines and routes.
* Different map styles: [OpenMapSurfer](http://korona.geog.uni-heidelberg.de/), [Mapnik](https://openstreetmap.org/),
[OpenCycleMap](https://opencyclemap.org/), [Hike & Bike map](http://hikebikemap.org/).
* [Public Transportation](http://openptmap.org/) and hillshading overlays.
* Search and calculate routes. Routes are fully draggable. (Uses [Nominatim](http://wiki.openstreetmap.org/wiki/Nominatim),
[OSRM](http://project-osrm.org/), [OpenRouteService](https://openrouteservice.org/),
[Leaflet.DraggableLines](https://github.com/FacilMap/Leaflet.DraggableLines).)
* Show GPX/KML/OSM/GeoJSON files on the map (use `Tools``Import File`, type a URL into the search field, or simply
drag and drop a file onto the map)
* Show additional information about places (for example opening hours or a link to the website). Press the map for
1 second somewhere to show information about what is there. (Uses [Nominatim](http://wiki.openstreetmap.org/wiki/Nominatim).)
* Zoom to the location of your device and follow it. (Uses [leaflet-locatecontrol](https://github.com/domoritz/leaflet-locatecontrol).)
* Create a collaborative map under a custom link where you and others can add markers, draw lines, save routes and
import GPX/KML/OSM/GeoJSON files
* Every map has three links, a read-only link, an editable link and an admin link. Everyone who has the link can access the map
(similar to [Etherpad](http://etherpad.org/), just for maps).
* Live collaboration. All changes to the map are immediately visible to everyone who is looking at it (using
[socket.io](http://socket.io/)).
* Markers and lines can have a name and description, which will be visible in a popup when clicking on it.
* Custom types of markers and lines can be defined, where in addition to the name and description, more text fields,
dropdowns and checkboxes can be added to be filled out. Custom dropdown fields can modify the style (colour and width)
of the markers and lines automatically, and a legend is generated automatically to explain what the different
styles stand for.
* The current map view can be saved for others to open.
* Map objects that do not fit a certain filter expression can be hidden (using [Filtrex](https://github.com/m93a/filtrex)).
* There is a modification history and changes can be undone.
* Can be easily run on your server or embedded into your website (see below).
Documentation
=============
On the client side, FacilMap relies heavily on [Vue.js](https://vuejs.org/), [Leaflet](http://leafletjs.com/)
and [Bootstrap](https://getbootstrap.com/). On the server side, it uses [Node.js](https://nodejs.org/),
[Sequelize](http://sequelizejs.com/) and [socket.io](http://socket.io/). FacilMap is written in [TypeScript](https://www.typescriptlang.org/).
For more information, have a look at the [documentation](https://docs.facilmap.org/).
Developer documentation
=======================
* [Embed FacilMap into your website](./frontend/README.md)
* [Run the FacilMap server yourself](./server/README.md)
* [Use the FacilMap client](./client/README.md) to receive changes and add/update/remove objects to/from a FacilMap
programmatically from a JavaScript web or server application.
Quick links:
* [User guide](https://docs.facilmap.org/users/)
* [Embed FacilMap into a website](https://docs.facilmap.org/administrators/embed.html)
* [Run the FacilMap server](https://docs.facilmap.org/administrators/server.html)
* [Use the FacilMap client](https://docs.facilmap.org/developers/client/) to programmatically modify objects on a collaborative map.
* [Dev setup](https://docs.facilmap.org/developers/development/dev-setup.html)
Quick start
-----------
===========
1. Run `yarn install` to install the dependencies
2. Run `yarn build` to build the JS bundles
3. Copy `config.env.example` to `config.env` and adjust the settings
4. Run `yarn server` inside the `server` directory
More details can be found under [Run the FacilMap server yourself](./server/README.md).
More details can be found in the [Administrator guide](https://docs.facilmap.org/administrators/server.html#standalone) and the [Developer guide](https://docs.facilmap.org/developers/development/dev-setup.html).
Support FacilMap
================
[Financial support](https://docs.facilmap.org/users/contribute/) is always welcome!

Wyświetl plik

@ -1,686 +0,0 @@
FacilMap client API
===================
* [Properties](#properties)
* [Events](#events)
* [Methods](#methods)
* [Types](#types-1)
Properties
----------
All objects that are received from the server are cached in properties of the client object.
All objects that can be part of a map have an `id`. Note that when an object is updated, the whole object is replaced in
these properties, so be careful to not cache outdated versions of objects:
```js
let myMarker = client.markers[myMarkerId];
setTimeout(() => {
// Bad! A client.markers[myMarkerId] might have been replaced if the marker
// has been changed in the meantime, and we are using the old version.
doSomethingWithMarker(myMarker);
}, 10000);
setTimeout(() => {
// Better! Always get objects directly from the client cache.
doSomethingWithMarker(client.markers[myMarkerId]);
});
// If you need to keep an object copy, make sure to keep it updated
client.on("marker", (marker) => {
if(marker.id == myMarkerId)
myMarker = marker;
});
```
### `padId`
The ID under which the client is connected to the map. Can be the read-only or a read-write ID of an existing map.
Note that the ID can be changed in the settings. If in case of a [`padData`](#paddata-1) event, the ID of the pad has
changed, this property is updated automatically.
_Type:_ string
### `readonly`
`true` if the map has been opened using its read-only ID. `false` if the map is writable.
_Type:_ boolean
### `writable`
`2` if the map has been opened using its admin ID, `1` if if has been opened using the writable ID, `0` if the map is read-only.
_Type:_ number
### `deleted`
`true` if the map was deleted while this client was connected to it.
### `padData`
The current settings of the map. `writeId` and/or `adminId` is null if if has been opened using another ID than the admin ID.
_Type:_ [padData](#paddata-2)
### `markers`
All markers that have been retrieved so far.
_Type:_ `{"<marker id>": `[`marker`](#marker-1)`}`
### `lines`
All lines and their track points that have been retrieved so far.
_Type:_ `{"<line id>": `[`line with trackPoints`](#line-1)`}`
### `views`
All views that have been retrieved so far.
_Type:_ `{"<view id>": `[`view`](#view-1)`}`
### `types`
All types that have been retrieved so far.
_Type:_ `{"<type id>": `[`type`](#type-1)`}`
### `history`
All history entries that have been retrieved so far. Note that you have to subscribe to the history using
[`listenToHistory()`](#listentohistory).
_Type:_ `{"<entry id>": `[`historyEntry`](#historyentry)`}`
### `route`
Information about the temporary route set using [`setRoute()`](#setRoutedata).
_Type:_ [`route`](#route-1)
### `serverError`
If the opening the pad failed ([`setPadId(padId)`](#setpadidpadid) promise got rejected), the error message is stored
in this property.
### `loading`
A number that indicates how many requests are currently pending. You can use this to show a loading spinner or disable certain
UI elements while the value is greater than 0.
Events
------
Subscribe to events using the [`on(eventName, function)`](#oneventname-function) method. Example:
```js
let client = new FacilMap.Client("https://facilmap.org/", "testPad");
client.on("padData", (padData) => {
document.title = padData.name;
});
```
### `connect`, `disconnect`, `connect_error`, `error`, `reconnect`, `reconnect_attempt`, `reconnect_error`, `reconnect_failed`
These events come from socket.io and are [documented there under the section “Events”](http://socket.io/docs/client-api/).
### `padData`
The settings of the map have changed or are retrieved for the first time.
Note that when this event is fired, the read-only and/or the read-write ID of the map might have changed. The [`padId`](#padid)
property is updated automatically.
_Type:_ [padData](#paddata-2)
### `deletePad`
The map has been deleted.
### `marker`
An existing marker is retrieved for the first time, has been modified, or a new marker has been created in the current bbox.
_Type:_ [marker](#marker-1)
### `deleteMarker`
A marker has been removed. This event is emitted for all markers in the map, even if they are outside of the current bbox
(in case that a marker outside of the current bbox is cached).
_Type:_ `{id: "<markerId>"}`
### `line`
An existing line is retrieved for the first time, has been modified, or a new line has been created. Note that line
objects only contain the line metadata, not its track points (those are handled separately as `linePoints`). This is why
all line objects of the map are sent to the client, regardless of the current bbox.
_Type:_ [line without trackPoints](#line-1)
### `deleteLine`
A line has been removed.
_Type:_ `{id: "<lineId>"}`
### `linePoints`
New track points for an existing line are retrieved after a change of bbox (`reset == false`), or the line has been
modified, so the new track points are retrieved (`reset == true`).
_Type:_ {
* __id__ (number): The ID of the line that these track points belong to
* __reset__ (boolean): Whether to remove all cached track points for this line (`true`) or to merge these track points
with the cached ones (`false`).
* __trackPoints__ (Array<[trackPoint](#trackpoint)>): The track points
}
### `view`
A view is retrieved for the first time, has been modified, or a new view has been created.
_Type:_ [view](#view-1)
### `deleteView`
A view has been removed.
_Type:_ `{id: "<viewId>"}`
### `type`
A type is retrieved for the first time, has been modified, or a new type has been created.
_Type:_ [type](#type-1)
### `deleteType`
A type has been removed.
_Type:_ `{id: "<typeId>"}`
### `history`
An entry of the modification history is retrieved for the first time, or a new entry has been created due to something
being modified. Note that this event is only fired when the client has subscribed using [`listenToHistory()`](#listentohistory).
_Type:_ [historyEntry](#historyentry)
### `routePoints`
New track points for the temporary route are retrieved after a change of bbox.
_Type:_ Array<[trackPoint](#trackpoint)>
### `loadStart`, `loadEnd`
This event is fired every time some request is sent to the server and when the response has arrived. It can be used to
display a loading indicator to the user. Note that multiple things can be loading at the same time. Example code:
```js
let loading = 0;
client.on("loadStart", () => {
++loading;
showLoadingIndicator();
});
client.on("loadEnd", () => {
if(--loading == 0)
hideLoadingIndicator();
});
```
Methods
-------
### `constructor(server, padId)`
Connects to the FacilMap server `server` and optionally opens the collaborative map with the ID `padId`. If the pad ID
is not set, it can be set later using [`setPadId(padId)`](#setpadidpadid) or using [`createPad(data)`](#createpaddata).
Setting the padId causes the server to send several objects, such as the map settings, all views, all types, and all
lines (just meta data, without line points).
If the connection to the server breaks down, a `disconnect` event will be emitted and socket.io will attempt to reconnect.
On successful reconnection, a `reconnect` and `connect` event will be fired.
* `server` (string): The URL of the FacilMap server, for example `https://facilmap.org/`
* `padId` (string, optional): The ID of the collaborative map to open
### `on(eventName, function)`
Registers a new [event](#events) handler.
* `eventName` (string): The name of the event
* `function` (function): The function that should be executed when the event occurs. If the event emits an object,
it will be passed to the function as the first parameter.
### `removeListener(eventName, function)`
Unregisters an event handler previously assigned using `on(eventName, function)`.
* `eventName` (string): The name of the event
* `function` (function): The function that was passed to `on(eventName, function)` when registering the handler
### `setPadId(padId)`
Opens the collaborative map with the ID `padId`.
This method can only be called once, and only if no `padId` has been passed to the constructor. If you want to open
a different map, you need to create a new instance of the client.
Setting the padId causes the server to send several objects, such as the map settings, all views, and all lines (just
meta data, without line points).
* `padId` (string): The ID of the collaborative map to open
* _returns_ (Promise): A promise that resolves when all objects have been received.
### `updateBbox(bbox)`
Updates the bbox. This will cause all markers and line points within the bbox (except the ones that were already in the
previous bbox, if there was one) to be received.
* __bbox__ ([bbox](#bbox) with zoom): The bbox that objects should be received for
* _returns_ (Promise): A promise that resolves when all objects have been received.
### `createPad(data)`
Creates a new collaborative map.
* `data` ([padData](#paddata-2)): The data of the new map, including the desired read-only and writable ID
* _returns_ (Promise): A promise that resolves when the map has been created, returning the new padData.
### `editPad(data)`
Update the metadata of the current map.
* `data` ([padData](#paddata-2)): The data of the map that should be modified. Fields that are not defined will not be
modified. To change the default view, set the `defaultViewId` property. The `defaultView` property is ignored.
* _returns_ (Promise): The new padData.
### `deletePad()`
Delete the current map irrevocably.
* _returns_ (Promise): An empty promise that resolves when the map has been deleted.
### `listenToHistory()`
Start listening to the modification history of the map. Calling this will cause multiple `history` objects to be
received (that describe the modification history until now), and new `history` objects will be received every time
something is modified (in addition to the modified object).
* _returns_ (Promise): A promise that resolves when all history objects have been received
### `stopListeningToHistory()`
Stop listening to the modification history of the map.
* _returns_ (Promise): A promise that resolves when the command has completed.
### `revertHistoryEntry(data)`
Undo a modification in the map. When a previously removed object is restored, it receives a new ID, and thus the object
IDs of all other history entries connected to this object are updated as well. This is why reverting a history entry
will cause the whole history to be received again (as if you were calling `listenToHistory()` again).
* `data` (`{id: "<historyEntryId>"}`)): The history object that should be reverted
* _returns_ (Promise): A promise that resolves when the command has completed and all new history objects have been received
### `disconnect()`
Empties all cached objects and disconnects from the server.
### `find(data)`
Search for places.
* `data` (object): An object with the following properties:
* `query` (string): The query string
* `loadUrls` (boolean): Whether to return the file if `query` is a URL
* `elevation` (boolean): Whether to find out the elevation of the result(s). Will make the search significantly slower.
* _returns_ (Promise<string|Array<[searchResult](#searchresult)>>): If `data.query` is a URL to a GPX/KML/OSM/GeoJSON
file, that file as a string, otherwise an array of search results.
### `findOnMap(data)`
Search for markers and lines inside the map.
* `data` (object): An object with the following properties:
* `query` (string): The query string
* _returns_ (Promise<Array<[Marker](#marker-1)|[Line](#line-1)>>) An array of (stripped down) marker and line objects.
The objects only contain the `id`, `name`, `typeId`, `lat`/`lon` (for markers), `left`/`top`/`right`/`bottom` (for
lines) properties, plus an additional `kind` property that is either `"marker"` or `"line"`.
### `getRoute(data)`
Calculate a route between two or more points.
* `data` (object): An object with the following properties:
* `destinations` (array): An array of at least two route points (objects with a `lat` and `lon` property)
* `mode` (string): `"car"`, `"bicycle"` or `"pedestrian"`
* _returns_ (Promise<[route](#route-1)>)
### `setRoute(data)`
Calculate a route between two or more points, but but do not return the track points of the route but cache them on the
server side and send them according to the client bbox. The properties of the route are saved in the [`route`](#route)
property and the trackPoints in `route.trackPoints`. Only one temporary route like this can be set at a time, when
calling `setRoute()` again, the existing route will be modified.
* `data` (object): An object with the following properties:
* `routePoints` (array): An array of at least two route points (objects with a `lat` and `lon` property)
* `mode` (string): `"car"`, `"bicycle"` or `"pedestrian"`
* `elevation` (boolean): `true` to get elevation data for the route
* _returns_ (Promise<[route](#route-1)>)
### `clearRoute()`
Clear the temporary route set via [`setRoute(data)`](#setroutedata).
* _returns_ (Promise)
### `lineToRoute(data)`
Call [`setRoute()`](#setroutedata) with the parameters of an existing line. Saves time, as the route does not need to be
recalculated.
* `data` (object): An object with the following properties:
* `id` (string): The ID of the line
* _returns_ (Promise<[route](#route-1)>)
### `exportRoute(data)`
Export the current route.
* `data` (object): An object with the following properties:
* `format` (string): One of the following:
* `gpx-trk`: GPX track (contains the whole course of the route)
* `gpx-rte`: GPX route (contains only the route points, and the navigation device will have to calculate the route)
* _returns_ (Promise&lt;string&gt;)
### `getMarker(data)`
Get the marker with the given ID.
* `data` (object): An object with the following properties:
* `id` (number): The ID of the marker to load
* _returns_ (Promise<[marker](#marker-1)>): The marker
### `addMarker(data)`
Create a marker.
* `data` ([marker](#marker-1)): The data of the marker to create. An `id` will be assigned by the server
* _returns_ (Promise<[marker](#marker-1)>): The marker as it is on the server, with an `id` assigned and possibly its
styles modified by the settings of its type.
### `editMarker(data)`
Update an existing marker.
* `data` ([marker](#marker-1)). The new marker data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
* _returns_ (Promise<[marker](#marker-1)>): The new marker. Might have some styles modified due to the settings of its type
### `deleteMarker(data)`
Delete an existing marker
* `data` (`{id: <markerId>}`): An object that contains the ID of the marker to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
### `getLineTemplate(data)`
Get a fake line object for a line with the given type. This can be used so that while the user is drawing a new line,
that line already has the right style.
* `data` (`{typeId: <typeId>}`): An object containing the type ID
* _returns_ (Promise<[line](#line-1)>): A fake line object with the styles of this type
### `addLine(data)`
Create a line.
* `data` ([line](#line-1)): The data of the line to create. An `id` will be assigned by the server
* _returns_ (Promise<[line](#line-1)>): The line as it is on the server, with an `id` assigned and possibly its
styles modified by the settings of its type.
### `editLine(data)`
Update an existing line.
* `data` ([line](#line-1)). The new line data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
* _returns_ (Promise<[line](#line-1)>): The new line. Might have some styles modified due to the settings of its type
### `deleteLine(data)`
Delete an existing line
* `data` (`{id: <lineId>}`): An object that contains the ID of the line to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
### `exportLine(data)`
Export a line.
* `data` (object): An object with the following properties:
* `id` (string): The ID of the line
* `format` (string): One of the following:
* `gpx-trk`: GPX track (contains the whole course of the route)
* `gpx-rte`: GPX route (contains only the route points, and the navigation device will have to calculate the route)
* _returns_ (Promise&lt;string&gt;)
### `addType(data)`
Create a type.
* `data` ([type](#type-1)): The data of the type to create. An `id` will be assigned by the server
* _returns_ (Promise<[type](#type-1)>): The type as it is on the server, with an `id` assigned.
### `editType(data)`
Update an existing type.
* `data` ([type](#type-1)). The new type data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
To rename a field, set the `oldName` property of the field object to the previous name and the `name` property to the
new name. To rename a dropdown entry, set the `oldValue` property to the old value and the `value` property to the new
value.
* _returns_ (Promise<[type](#type-1)>): The new type.
### `deleteType(data)`
Delete an existing type
* `data` (`{id: <typeId>}`): An object that contains the ID of the type to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
### `addView(data)`
Create a view.
* `data` ([view](#view-1)): The data of the view to create. An `id` will be assigned by the server
* _returns_ (Promise<[view](#view-1)>): The view as it is on the server, with an `id` assigned.
### `editView(data)`
Update an existing view.
* `data` ([view](#view-1)). The new view data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
* _returns_ (Promise<[view](#view-1)>): The new view.
### `deleteView(data)`
Delete an existing view
* `data` (`{id: <viewId>}`): An object that contains the ID of the view to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
### `geoip()`
Returns an approximate location for the IP address of the client.
* _returns_ (Promise<{top,right,bottom,left}>) A promise that resolves to a bounding box that includes the location of
the client
Types
-----
### bbox
A bounding box that describes which part of the map the user is currently viewing.
* `top` (number, min: -90, max: 90): The latitude of the north end of the box
* `bottom` (number, min: -90, max: 90): The latitude of the south end of the box
* `left` (number, min: -180, max: 180): The longitude of the west end of the box
* `right` (number, min: -180, max: 180): The longitude of the east end of the box
* `zoom` (number, min: 1, max: 20): The current zoom level. This is relevant for the density of track points that
should be received.
### marker
* `id` (number): The ID of this marker
* `lat` (number, min: -90, max: 90): The latitude of this marker
* `lon` (number, min: -180, max: 180): The longitude of this marker
* `name` (string): The name of this marker
* `colour` (string): The colour of this marker as a 6-digit hex value, for example `ff0000`
* `size` (number, min: 15): The height of the marker in pixels
* `symbol` (string): The symbol code for the marker. Default is an empty string.
* `shape` (string): The shape code for the marker. Default is an empty string (equals `"drop"`).
* `elevation` (number): The elevation of this marker in metres (set by the server)
* `typeId` (number): The ID of the type of this marker
* `data` (`{"key", "value"}`): The filled out form fields of the marker
### line
Each line has `routePoints` and `trackPoints`. The `routePoints` are the start, end and via points that the user created
for that line, the `trackPoints` describe how the line should be drawn. If no routing is used, `routePoints` and
`trackPoints` are equal, but with routing, there will be a lot more `trackPoints` than `routePoints`.
When creating or updating a line, the `trackPoints`, `distance` and `time` properties are automatically calculated by
the server. Only when the routing mode is `track`, the `trackPoints` can be specified by hand (meant for importing
existing tracks, for example from a GPX file). The `idx`, `zoom` and `ele` properties of the track points are added by
the server automatically.
Note that `line` objects coming from the server dont contain the `trackPoints` property, but the track points are sent
separately through `linePoints` events.
* `id` (number): The ID of this line
* `routePoints` (`[{lat, lon}]`): The route points
* `mode` (string): The routing mode, an empty string for no routing, or `car`, `bicycle`, `pedestrian`, or `track`
* `colour` (string): The colour of this marker as a 6-digit hex value, for example `0000ff`
* `width` (number, min: 1): The width of the line
* `name` (string): The name of the line
* `distance` (number): The distance of the line in kilometers (set by the server)
* `ascent`, `descent` (number): The total ascent/descent of the line in metres (set by the server)
* `time` (number): The time it takes to travel the route in seconds (only if routing mode is `car`, `bicycle` or `pedestrian`) (set by the server)
* `left`, `top`, `right`, `bottom` (number): The bounding box of the line (set by the server)
* `typeId` (number): The ID of the type of this line
* `data` (`{"key", "value"}`): The filled out form fields of the line
* `trackPoints`:
* In the `lines` property of the client, an object of the format `{"<idx>": trackPoint}`
* When creating/updating a line with the routing mode `track`, an array of the format `[trackPoint]`
### trackPoint
All track points have a `zoom` level and are only received when the zoom level of the current bbox is at least that
level. This makes sure that at a small zoom level, only a low resolution of the line has to be downloaded. When zooming
in, only the additional track points are retrieved. They can be merged into the already retrieved track points using
their `idx` property.
* `idx` (number): The index of this track point in the list of all track points of this line
* `lat` (number, min: -90, max: 90): The latitude of this point
* `lon` (number, min: -180, max: 180): The longitude of this point
* `zoom` (number, min: 1, max: 20): The miminum zoom level from which this track point makes sense to show
* `ele` (number): The elevation of this track point in metres (set by the server). Not set for high zoom levels.
### padData
* `id` (string): The read-only ID of this map
* `writeId` (string): The read-write ID of this map
* `adminId` (string): The admin ID of this map
* `name` (string): The name of this map
* `searchEngines` (boolean): Whether search engines may index the read-only version of this map
* `description` (string): The description for search engines
* `clusterMarkers` (boolean): Whether many markers close to each other should be grouped together
* `legend1`, `legend2` (string): Markdown free text to be shown above and below the legend
* `defaultViewId` (number): The ID of the default view (if any)
* `defaultView` ([view](#view-1)): A copy of the default view object
### view
* `id` (number): The ID of this view
* `name` (string): The name of this view
* `baseLayer` (string): The key of the base layer in this view
* `layers` ([string]): An array of activated overlays in this view
* `top`, `bottom`, `left`, `right`: The [bbox](#bbox) of this view
* `filter` (string): If set, filter the objects according to this filtrex expression
### historyEntry
* `id` (number): The ID of this history entry
* `time` (Date): The time when the modification was done
* `type` (string): The type of object that was modified, one of `Marker`, `Line`, `View`, `Type`, `Pad`
* `action` (string): The action that was done, one of `create`, `update`, `delete`
* `objectId` (number): The ID of the object that was modified (null if the object was the map itself)
* `objectBefore` (object): The object before the modification (null if `action` is `create`)
* `objectAfter` (object): The object after the modification (null if `action` is `delete`)
### type
* `id` (number): The ID of this type
* `name` (string): The name of this type
* `type` (string): `marker` or `line`
* `defaultColour`, `defaultSize`, `defaultSymbol`, `defaultWidth`, `defaultMode` (string/number): Default values for the
different object properties
* `colourFixed`, `sizeFixed`, `symbolFixed`, `shapeFixed`, `widthFixed`, `modeFixed` (boolean): Whether those values are fixed and
cannot be changed for an individual object
* `fields` ([object]): The form fields for this type. Each field has the following properties:
* `name` (string): The name of the field. This is at the same time the key in the `data` properties of markers and lines
* `oldName` (string): When renaming a field (using [`editType(data)`](#edittypedata)), specify the former name here
* `type` (string): The type of field, one of `textarea`, `dropdown`, `checkbox`, `input`
* `controlColour`, `controlSize`, `controlSymbol`, `controlShape`, `controlWidth` (boolean): If this field is a dropdown, whether
the different options set a specific property on the object
* `default` (string/boolean): The default value of this field
* `options` ([object]): If this field is a dropdown, an array of objects with the following properties:
* `value` (string): The value of this option.
* `oldValue` (string): When renaming a dropdown option (using [`editType(data)`](#edittypedata)), specify the
former value here
* `colour`, `size`, `shape`, `symbol`, `width` (string/number): The property value if this field controls that property
### searchResult
* `short_name` (string): Name of the result
* `display_name` (string): Name with address
* `address` (string): Only the address
* `boundingbox` ([bbox](#bbox)): bbox that has a good view onto the result. Might be null if `zoom` is set.
* `lat`, `lon` (number): Position of the search result.
* `zoom` (number): Zoom level at which there is a good view onto the result. Might be null if `boundingbox` is set.
* `extratags` (object): Extra OSM tags that might be useful
* `geojson` (object): GeoJSON if the result has a shape
* `icon` (string): Symbol key of the result
* `type` (string): Type of the result
* `id` (string): If the result is an OSM object, the ID of the OSM object, prefixed by `n` (node), `w` (way) or `r` (relation)
* `ele` (number): Elevation in meters
### route
* `routePoints` (array): Array of route points (objects with `lon` and `lat` properties)
* `mode` (string): Route mode: `"car"`, `"bicycle"`, `"pedestrian"` or an empty string `""` for a direct line
* `trackPoints` (array): An array of track points (objects with a `lon`, `lat`, `ele`, `idx` property and also a `zoom`
property that indicates from which zoom level the track point should be shown (to avoid an unnecessarily high resolution))
* `distance` (number): The distance of the route in kilometers
* `time` (number): The time it takes to travel the route in seconds
* `ascent` (number): The total meters of climb
* `descent` (number) The total meters of drop

Wyświetl plik

@ -1,89 +1,3 @@
Using the FacilMap client
=========================
**facilmap-client** is a library that acts as a client to the [FacilMap](https://github.com/facilmap/facilmap) server and makes it possible to retrieve and modify objects on a collaborative map.
The FacilMap client makes a connection to the FacilMap server using [socket.io](http://socket.io/) and
automatically receives updates when markers, lines, the map settings, or any other part of a map is created,
changed or removed. When connecting to the map using the writable ID, it it also makes it possible to make
any modifications to the map that you could make through the web interface, such as creating/changing/removing
markers, lines and views and changing the map settings.
One instance of the Client class represents one connection to one specific collaborative map on one specific
FacilMap server. To receive markers and lines, a bbox has to be set, and only the markers and line points within
that bbox will be received. The bbox can be changed (for example, if the user drags the map), which causes objects
from the new bbox to be received. The Client instance will store all objects that it receives in its [properties](./API.md#properties).
Note that in the methods of the client, a collaborative map will be referred to as __pad__. This is because the
collaborative part of FacilMap used to be a separate software called FacilPad.
Setting it up
-------------
Install facilmap-client as a dependency using npm or yarn:
```bash
npm install -S facilmap-client
```
or load the client directly from facilmap.org (along with socket.io, which is needed by facilmap-client):
```html
<script src="https://unpkg.com/socket.io-client@4"></script>
<script src="https://unpkg.com/facilmap-client@3"></script>
```
The client class will be available as the global `FacilMap.Client` variable.
### Development
Make sure you have yarn installed. Run `yarn install` to install the dependencies and `yarn run build`
to create the bundle in `dist/client.js`.
Setting up a connection
-----------------------
```js
let client = new FacilMap.Client("https://facilmap.org/");
client.setPadId("myMapId").then((padData) => {
console.log(padData);
}).catch((err) => {
console.error(err.stack);
});
```
Using it
--------
A detailed description of all the methods and data types can be found in [API](./API.md).
Change detection
----------------
When the FacilMap server sends an event to the client that an object has been created, changed or deleted, the client emits the
event and also persists it in its properties. So you have two ways to access the map data: By listening to the map events and
persisting the data somewhere else, or by accessing the properties on the Client object.
If you are using a UI framework that relies on a change detection mechanism (such as Vue.js or Angular), you can override the methods
`_set` and `_delete`. facilmap-client consistently uses these to update any data on its properties.
In Vue.js, it could look like this:
```javascript
let client = new FacilMap.Client("https://facilmap.org/");
client._set = Vue.set;
client._delete = Vue.delete;
```
In Angular.js, it could look like this:
```javascript
let client = new FacilMap.Client("https://facilmap.org/");
client._set = (object, key, value) => { $rootScope.$apply(() => { object[key] = value; }); };
client._delete = (object, key) => { $rootScope.$apply(() => { delete object[key]; }); };
```
This way your UI framework will detect changes to any properties on the client, and you can reference values like `client.padData.name`,
`client.disconnected` and `client.loading` in your UI components.
More information can be found in the [documentation](https://docs.facilmap.org/developers/client/).

Wyświetl plik

@ -64,7 +64,7 @@ module.exports = {
"types/",
"legend/",
"views/",
"filters/",
"filter/",
"history/",
"export/",
"import/",
@ -82,6 +82,27 @@ module.exports = {
"server"
]
}
],
'/developers/': [
"",
{
title: 'Client',
collapsable: false,
children: [
"client/",
"client/properties",
"client/events",
"client/methods",
"client/types"
]
},
{
title: 'Development',
collapsable: false,
children: [
"development/dev-setup.md"
]
}
]
}
},

Wyświetl plik

@ -0,0 +1,4 @@
# Overview
* Use the [FacilMap client](./client/) to programmatically access and modify a collaborative map.
* Read about the [dev setup](./development/dev-setup) to start contributing to the FacilMap code.

Wyświetl plik

@ -0,0 +1,78 @@
# Overview
The FacilMap client makes a connection to the FacilMap server using [socket.io](http://socket.io/) and
automatically receives updates when markers, lines, the map settings, or any other part of a map is created,
changed or removed. When connecting to the map using the writable ID, it it also makes it possible to make
any modifications to the map that you could make through the web interface, such as creating/changing/removing
markers, lines and views and changing the map settings.
One instance of the Client class represents one connection to one specific collaborative map on one specific
FacilMap server. To receive markers and lines, a bbox has to be set, and only the markers and line points within
that bbox will be received. The bbox can be changed (for example, if the user drags the map), which causes objects
from the new bbox to be received. The Client instance will store all objects that it receives in its [properties](./properties).
Note that in the methods of the client, a collaborative map will be referred to as __pad__. This is because the
collaborative part of FacilMap used to be a separate software called FacilPad.
## Setting it up
Install facilmap-client as a dependency using npm or yarn:
```bash
npm install -S facilmap-client
```
or load the client directly from facilmap.org (along with socket.io, which is needed by facilmap-client):
```html
<script src="https://unpkg.com/socket.io-client@4"></script>
<script src="https://unpkg.com/facilmap-client@3"></script>
```
The client class will be available as the global `FacilMap.Client` variable.
## Setting up a connection
```js
let client = new FacilMap.Client("https://facilmap.org/");
client.setPadId("myMapId").then((padData) => {
console.log(padData);
}).catch((err) => {
console.error(err.stack);
});
```
## Using it
A detailed description of all the [properties](./properties), [events](./events), [methods](./methods) and [Types](./types) can be found in the respective sections of the documentation.
## Change detection
When the FacilMap server sends an event to the client that an object has been created, changed or deleted, the client emits the
event and also persists it in its properties. So you have two ways to access the map data: By listening to the map events and
persisting the data somewhere else, or by accessing the properties on the Client object.
If you are using a UI framework that relies on a change detection mechanism (such as Vue.js or Angular), you can override the methods
`_set` and `_delete`. facilmap-client consistently uses these to update any data on its properties.
In Vue.js, it could look like this:
```javascript
let client = new FacilMap.Client("https://facilmap.org/");
client._set = Vue.set;
client._delete = Vue.delete;
```
In Angular.js, it could look like this:
```javascript
let client = new FacilMap.Client("https://facilmap.org/");
client._set = (object, key, value) => { $rootScope.$apply(() => { object[key] = value; }); };
client._delete = (object, key) => { $rootScope.$apply(() => { delete object[key]; }); };
```
This way your UI framework will detect changes to any properties on the client, and you can reference values like `client.padData.name`,
`client.disconnected` and `client.loading` in your UI components.

Wyświetl plik

@ -0,0 +1,121 @@
# Events
Subscribe to events using the [`on(eventName, function)`](./methods#on-eventname-function) method. Example:
```js
let client = new FacilMap.Client("https://facilmap.org/", "testPad");
client.on("padData", (padData) => {
document.title = padData.name;
});
```
## `connect`, `disconnect`, `connect_error`, `error`, `reconnect`, `reconnect_attempt`, `reconnect_error`, `reconnect_failed`
These events come from socket.io and are [documented there under the section “Events”](http://socket.io/docs/client-api/).
## `padData`
The settings of the map have changed or are retrieved for the first time.
Note that when this event is fired, the read-only and/or the read-write ID of the map might have changed. The [`padId`](./properties#padid)
property is updated automatically.
_Type:_ [padData](./types#paddata)
## `deletePad`
The map has been deleted.
## `marker`
An existing marker is retrieved for the first time, has been modified, or a new marker has been created in the current bbox.
_Type:_ [marker](./types#marker)
## `deleteMarker`
A marker has been removed. This event is emitted for all markers in the map, even if they are outside of the current bbox
(in case that a marker outside of the current bbox is cached).
_Type:_ `{id: "<markerId>"}`
## `line`
An existing line is retrieved for the first time, has been modified, or a new line has been created. Note that line
objects only contain the line metadata, not its track points (those are handled separately as `linePoints`). This is why
all line objects of the map are sent to the client, regardless of the current bbox.
_Type:_ [line without trackPoints](./types#line)
## `deleteLine`
A line has been removed.
_Type:_ `{id: "<lineId>"}`
## `linePoints`
New track points for an existing line are retrieved after a change of bbox (`reset == false`), or the line has been
modified, so the new track points are retrieved (`reset == true`).
_Type:_ {
* __id__ (number): The ID of the line that these track points belong to
* __reset__ (boolean): Whether to remove all cached track points for this line (`true`) or to merge these track points
with the cached ones (`false`).
* __trackPoints__ (Array<[trackPoint](./types#trackpoint)>): The track points
}
## `view`
A view is retrieved for the first time, has been modified, or a new view has been created.
_Type:_ [view](./types#view)
## `deleteView`
A view has been removed.
_Type:_ `{id: "<viewId>"}`
## `type`
A type is retrieved for the first time, has been modified, or a new type has been created.
_Type:_ [type](./types#type)
## `deleteType`
A type has been removed.
_Type:_ `{id: "<typeId>"}`
## `history`
An entry of the modification history is retrieved for the first time, or a new entry has been created due to something
being modified. Note that this event is only fired when the client has subscribed using [`listenToHistory()`](./methods#listentohistory).
_Type:_ [historyEntry](./types#historyentry)
## `routePoints`
New track points for the temporary route are retrieved after a change of bbox.
_Type:_ Array<[trackPoint](./types#trackpoint)>
## `loadStart`, `loadEnd`
This event is fired every time some request is sent to the server and when the response has arrived. It can be used to
display a loading indicator to the user. Note that multiple things can be loading at the same time. Example code:
```js
let loading = 0;
client.on("loadStart", () => {
++loading;
showLoadingIndicator();
});
client.on("loadEnd", () => {
if(--loading == 0)
hideLoadingIndicator();
});
```

Wyświetl plik

@ -0,0 +1,294 @@
# Methods
## `constructor(server, padId)`
Connects to the FacilMap server `server` and optionally opens the collaborative map with the ID `padId`. If the pad ID
is not set, it can be set later using [`setPadId(padId)`](#setpadid-padid) or using [`createPad(data)`](#createpad-data).
Setting the padId causes the server to send several objects, such as the map settings, all views, all types, and all
lines (just meta data, without line points).
If the connection to the server breaks down, a `disconnect` event will be emitted and socket.io will attempt to reconnect.
On successful reconnection, a `reconnect` and `connect` event will be fired.
* `server` (string): The URL of the FacilMap server, for example `https://facilmap.org/`
* `padId` (string, optional): The ID of the collaborative map to open
## `on(eventName, function)`
Registers a new [event](./events) handler.
* `eventName` (string): The name of the event
* `function` (function): The function that should be executed when the event occurs. If the event emits an object,
it will be passed to the function as the first parameter.
## `removeListener(eventName, function)`
Unregisters an event handler previously assigned using `on(eventName, function)`.
* `eventName` (string): The name of the event
* `function` (function): The function that was passed to `on(eventName, function)` when registering the handler
## `setPadId(padId)`
Opens the collaborative map with the ID `padId`.
This method can only be called once, and only if no `padId` has been passed to the constructor. If you want to open
a different map, you need to create a new instance of the client.
Setting the padId causes the server to send several objects, such as the map settings, all views, and all lines (just
meta data, without line points).
* `padId` (string): The ID of the collaborative map to open
* _returns_ (Promise): A promise that resolves when all objects have been received.
## `updateBbox(bbox)`
Updates the bbox. This will cause all markers and line points within the bbox (except the ones that were already in the
previous bbox, if there was one) to be received.
* __bbox__ ([bbox](./types#bbox) with zoom): The bbox that objects should be received for
* _returns_ (Promise): A promise that resolves when all objects have been received.
## `createPad(data)`
Creates a new collaborative map.
* `data` ([padData](./types#paddata)): The data of the new map, including the desired read-only and writable ID
* _returns_ (Promise): A promise that resolves when the map has been created, returning the new padData.
## `editPad(data)`
Update the metadata of the current map.
* `data` ([padData](./types#paddata)): The data of the map that should be modified. Fields that are not defined will not be
modified. To change the default view, set the `defaultViewId` property. The `defaultView` property is ignored.
* _returns_ (Promise): The new padData.
## `deletePad()`
Delete the current map irrevocably.
* _returns_ (Promise): An empty promise that resolves when the map has been deleted.
## `listenToHistory()`
Start listening to the modification history of the map. Calling this will cause multiple `history` objects to be
received (that describe the modification history until now), and new `history` objects will be received every time
something is modified (in addition to the modified object).
* _returns_ (Promise): A promise that resolves when all history objects have been received
## `stopListeningToHistory()`
Stop listening to the modification history of the map.
* _returns_ (Promise): A promise that resolves when the command has completed.
## `revertHistoryEntry(data)`
Undo a modification in the map. When a previously removed object is restored, it receives a new ID, and thus the object
IDs of all other history entries connected to this object are updated as well. This is why reverting a history entry
will cause the whole history to be received again (as if you were calling `listenToHistory()` again).
* `data` (`{id: "<historyEntryId>"}`)): The history object that should be reverted
* _returns_ (Promise): A promise that resolves when the command has completed and all new history objects have been received
## `disconnect()`
Empties all cached objects and disconnects from the server.
## `find(data)`
Search for places.
* `data` (object): An object with the following properties:
* `query` (string): The query string
* `loadUrls` (boolean): Whether to return the file if `query` is a URL
* `elevation` (boolean): Whether to find out the elevation of the result(s). Will make the search significantly slower.
* _returns_ (Promise<string|Array<[searchResult](./types#searchresult)>>): If `data.query` is a URL to a GPX/KML/OSM/GeoJSON
file, that file as a string, otherwise an array of search results.
## `findOnMap(data)`
Search for markers and lines inside the map.
* `data` (object): An object with the following properties:
* `query` (string): The query string
* _returns_ (Promise<Array<[Marker](./types#marker)|[Line](./types#line)>>) An array of (stripped down) marker and line objects.
The objects only contain the `id`, `name`, `typeId`, `lat`/`lon` (for markers), `left`/`top`/`right`/`bottom` (for
lines) properties, plus an additional `kind` property that is either `"marker"` or `"line"`.
## `getRoute(data)`
Calculate a route between two or more points.
* `data` (object): An object with the following properties:
* `destinations` (array): An array of at least two route points (objects with a `lat` and `lon` property)
* `mode` (string): `"car"`, `"bicycle"` or `"pedestrian"`
* _returns_ (Promise<[route](./types#route)>)
## `setRoute(data)`
Calculate a route between two or more points, but but do not return the track points of the route but cache them on the
server side and send them according to the client bbox. The properties of the route are saved in the [`route`](./properties#route)
property and the trackPoints in `route.trackPoints`. Only one temporary route like this can be set at a time, when
calling `setRoute()` again, the existing route will be modified.
* `data` (object): An object with the following properties:
* `routePoints` (array): An array of at least two route points (objects with a `lat` and `lon` property)
* `mode` (string): `"car"`, `"bicycle"` or `"pedestrian"`
* `elevation` (boolean): `true` to get elevation data for the route
* _returns_ (Promise<[route](./types#route)>)
## `clearRoute()`
Clear the temporary route set via [`setRoute(data)`](#setroute-data).
* _returns_ (Promise)
## `lineToRoute(data)`
Call [`setRoute()`](#setroute-data) with the parameters of an existing line. Saves time, as the route does not need to be
recalculated.
* `data` (object): An object with the following properties:
* `id` (string): The ID of the line
* _returns_ (Promise<[route](./types#route)>)
## `exportRoute(data)`
Export the current route.
* `data` (object): An object with the following properties:
* `format` (string): One of the following:
* `gpx-trk`: GPX track (contains the whole course of the route)
* `gpx-rte`: GPX route (contains only the route points, and the navigation device will have to calculate the route)
* _returns_ (Promise&lt;string&gt;)
## `getMarker(data)`
Get the marker with the given ID.
* `data` (object): An object with the following properties:
* `id` (number): The ID of the marker to load
* _returns_ (Promise<[marker](./types#marker)>): The marker
## `addMarker(data)`
Create a marker.
* `data` ([marker](./types#marker)): The data of the marker to create. An `id` will be assigned by the server
* _returns_ (Promise<[marker](./types#marker)>): The marker as it is on the server, with an `id` assigned and possibly its
styles modified by the settings of its type.
## `editMarker(data)`
Update an existing marker.
* `data` ([marker](./types#marker)). The new marker data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
* _returns_ (Promise<[marker](./types#marker)>): The new marker. Might have some styles modified due to the settings of its type
## `deleteMarker(data)`
Delete an existing marker
* `data` (`{id: <markerId>}`): An object that contains the ID of the marker to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
## `getLineTemplate(data)`
Get a fake line object for a line with the given type. This can be used so that while the user is drawing a new line,
that line already has the right style.
* `data` (`{typeId: <typeId>}`): An object containing the type ID
* _returns_ (Promise<[line](./types#line)>): A fake line object with the styles of this type
## `addLine(data)`
Create a line.
* `data` ([line](./types#line)): The data of the line to create. An `id` will be assigned by the server
* _returns_ (Promise<[line](./types#line)>): The line as it is on the server, with an `id` assigned and possibly its
styles modified by the settings of its type.
## `editLine(data)`
Update an existing line.
* `data` ([line](./types#line)). The new line data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
* _returns_ (Promise<[line](./types#line)>): The new line. Might have some styles modified due to the settings of its type
## `deleteLine(data)`
Delete an existing line
* `data` (`{id: <lineId>}`): An object that contains the ID of the line to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
## `exportLine(data)`
Export a line.
* `data` (object): An object with the following properties:
* `id` (string): The ID of the line
* `format` (string): One of the following:
* `gpx-trk`: GPX track (contains the whole course of the route)
* `gpx-rte`: GPX route (contains only the route points, and the navigation device will have to calculate the route)
* _returns_ (Promise&lt;string&gt;)
## `addType(data)`
Create a type.
* `data` ([type](./types#type)): The data of the type to create. An `id` will be assigned by the server
* _returns_ (Promise<[type](./types#type)>): The type as it is on the server, with an `id` assigned.
## `editType(data)`
Update an existing type.
* `data` ([type](./types#type)). The new type data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
To rename a field, set the `oldName` property of the field object to the previous name and the `name` property to the
new name. To rename a dropdown entry, set the `oldValue` property to the old value and the `value` property to the new
value.
* _returns_ (Promise<[type](./types#type)>): The new type.
## `deleteType(data)`
Delete an existing type
* `data` (`{id: <typeId>}`): An object that contains the ID of the type to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
## `addView(data)`
Create a view.
* `data` ([view](./types#view)): The data of the view to create. An `id` will be assigned by the server
* _returns_ (Promise<[view](./types#view)>): The view as it is on the server, with an `id` assigned.
## `editView(data)`
Update an existing view.
* `data` ([view](./types#view)). The new view data. Fields that are not defined will not be unmodified. Only `id` needs
to be defined.
* _returns_ (Promise<[view](./types#view)>): The new view.
## `deleteView(data)`
Delete an existing view
* `data` (`{id: <viewId>}`): An object that contains the ID of the view to be removed
* _returns_ (Promise): A promise that resolves when the operation has completed
## `geoip()`
Returns an approximate location for the IP address of the client.
* _returns_ (Promise<{top,right,bottom,left}>) A promise that resolves to a bounding box that includes the location of
the client

Wyświetl plik

@ -0,0 +1,106 @@
# Properties
All objects that are received from the server are cached in properties of the client object.
All objects that can be part of a map have an `id`. Note that when an object is updated, the whole object is replaced in
these properties, so be careful to not cache outdated versions of objects:
```js
let myMarker = client.markers[myMarkerId];
setTimeout(() => {
// Bad! A client.markers[myMarkerId] might have been replaced if the marker
// has been changed in the meantime, and we are using the old version.
doSomethingWithMarker(myMarker);
}, 10000);
setTimeout(() => {
// Better! Always get objects directly from the client cache.
doSomethingWithMarker(client.markers[myMarkerId]);
});
// If you need to keep an object copy, make sure to keep it updated
client.on("marker", (marker) => {
if(marker.id == myMarkerId)
myMarker = marker;
});
```
## `padId`
The ID under which the client is connected to the map. Can be the read-only or a read-write ID of an existing map.
Note that the ID can be changed in the settings. If in case of a [`padData`](./events#paddata) event, the ID of the pad has
changed, this property is updated automatically.
_Type:_ string
## `readonly`
`true` if the map has been opened using its read-only ID. `false` if the map is writable.
_Type:_ boolean
## `writable`
`2` if the map has been opened using its admin ID, `1` if if has been opened using the writable ID, `0` if the map is read-only.
_Type:_ number
## `deleted`
`true` if the map was deleted while this client was connected to it.
## `padData`
The current settings of the map. `writeId` and/or `adminId` is null if if has been opened using another ID than the admin ID.
_Type:_ [padData](./types#paddata)
## `markers`
All markers that have been retrieved so far.
_Type:_ `{"<marker id>": `[`marker`](./types#marker)`}`
## `lines`
All lines and their track points that have been retrieved so far.
_Type:_ `{"<line id>": `[`line with trackPoints`](./types#line)`}`
## `views`
All views that have been retrieved so far.
_Type:_ `{"<view id>": `[`view`](./types#view)`}`
## `types`
All types that have been retrieved so far.
_Type:_ `{"<type id>": `[`type`](./types#type)`}`
## `history`
All history entries that have been retrieved so far. Note that you have to subscribe to the history using
[`listenToHistory()`](./methods#listentohistory).
_Type:_ `{"<entry id>": `[`historyEntry`](./types#historyentry)`}`
## `route`
Information about the temporary route set using [`setRoute()`](./methods#setroute-data).
_Type:_ [`route`](./types#route)
## `serverError`
If the opening the pad failed ([`setPadId(padId)`](./methods#setpadid-padid) promise got rejected), the error message is stored
in this property.
## `loading`
A number that indicates how many requests are currently pending. You can use this to show a loading spinner or disable certain
UI elements while the value is greater than 0.

Wyświetl plik

@ -0,0 +1,149 @@
# Types
## bbox
A bounding box that describes which part of the map the user is currently viewing.
* `top` (number, min: -90, max: 90): The latitude of the north end of the box
* `bottom` (number, min: -90, max: 90): The latitude of the south end of the box
* `left` (number, min: -180, max: 180): The longitude of the west end of the box
* `right` (number, min: -180, max: 180): The longitude of the east end of the box
* `zoom` (number, min: 1, max: 20): The current zoom level. This is relevant for the density of track points that
should be received.
## marker
* `id` (number): The ID of this marker
* `lat` (number, min: -90, max: 90): The latitude of this marker
* `lon` (number, min: -180, max: 180): The longitude of this marker
* `name` (string): The name of this marker
* `colour` (string): The colour of this marker as a 6-digit hex value, for example `ff0000`
* `size` (number, min: 15): The height of the marker in pixels
* `symbol` (string): The symbol code for the marker. Default is an empty string.
* `shape` (string): The shape code for the marker. Default is an empty string (equals `"drop"`).
* `elevation` (number): The elevation of this marker in metres (set by the server)
* `typeId` (number): The ID of the type of this marker
* `data` (`{"key", "value"}`): The filled out form fields of the marker
## line
Each line has `routePoints` and `trackPoints`. The `routePoints` are the start, end and via points that the user created
for that line, the `trackPoints` describe how the line should be drawn. If no routing is used, `routePoints` and
`trackPoints` are equal, but with routing, there will be a lot more `trackPoints` than `routePoints`.
When creating or updating a line, the `trackPoints`, `distance` and `time` properties are automatically calculated by
the server. Only when the routing mode is `track`, the `trackPoints` can be specified by hand (meant for importing
existing tracks, for example from a GPX file). The `idx`, `zoom` and `ele` properties of the track points are added by
the server automatically.
Note that `line` objects coming from the server dont contain the `trackPoints` property, but the track points are sent
separately through `linePoints` events.
* `id` (number): The ID of this line
* `routePoints` (`[{lat, lon}]`): The route points
* `mode` (string): The routing mode, an empty string for no routing, or `car`, `bicycle`, `pedestrian`, or `track`
* `colour` (string): The colour of this marker as a 6-digit hex value, for example `0000ff`
* `width` (number, min: 1): The width of the line
* `name` (string): The name of the line
* `distance` (number): The distance of the line in kilometers (set by the server)
* `ascent`, `descent` (number): The total ascent/descent of the line in metres (set by the server)
* `time` (number): The time it takes to travel the route in seconds (only if routing mode is `car`, `bicycle` or `pedestrian`) (set by the server)
* `left`, `top`, `right`, `bottom` (number): The bounding box of the line (set by the server)
* `typeId` (number): The ID of the type of this line
* `data` (`{"key", "value"}`): The filled out form fields of the line
* `trackPoints`:
* In the `lines` property of the client, an object of the format `{"<idx>": trackPoint}`
* When creating/updating a line with the routing mode `track`, an array of the format `[trackPoint]`
## trackPoint
All track points have a `zoom` level and are only received when the zoom level of the current bbox is at least that
level. This makes sure that at a small zoom level, only a low resolution of the line has to be downloaded. When zooming
in, only the additional track points are retrieved. They can be merged into the already retrieved track points using
their `idx` property.
* `idx` (number): The index of this track point in the list of all track points of this line
* `lat` (number, min: -90, max: 90): The latitude of this point
* `lon` (number, min: -180, max: 180): The longitude of this point
* `zoom` (number, min: 1, max: 20): The miminum zoom level from which this track point makes sense to show
* `ele` (number): The elevation of this track point in metres (set by the server). Not set for high zoom levels.
## padData
* `id` (string): The read-only ID of this map
* `writeId` (string): The read-write ID of this map
* `adminId` (string): The admin ID of this map
* `name` (string): The name of this map
* `searchEngines` (boolean): Whether search engines may index the read-only version of this map
* `description` (string): The description for search engines
* `clusterMarkers` (boolean): Whether many markers close to each other should be grouped together
* `legend1`, `legend2` (string): Markdown free text to be shown above and below the legend
* `defaultViewId` (number): The ID of the default view (if any)
* `defaultView` ([view](#view)): A copy of the default view object
## view
* `id` (number): The ID of this view
* `name` (string): The name of this view
* `baseLayer` (string): The key of the base layer in this view
* `layers` ([string]): An array of activated overlays in this view
* `top`, `bottom`, `left`, `right`: The [bbox](#bbox) of this view
* `filter` (string): If set, filter the objects according to this filtrex expression
## historyEntry
* `id` (number): The ID of this history entry
* `time` (Date): The time when the modification was done
* `type` (string): The type of object that was modified, one of `Marker`, `Line`, `View`, `Type`, `Pad`
* `action` (string): The action that was done, one of `create`, `update`, `delete`
* `objectId` (number): The ID of the object that was modified (null if the object was the map itself)
* `objectBefore` (object): The object before the modification (null if `action` is `create`)
* `objectAfter` (object): The object after the modification (null if `action` is `delete`)
## type
* `id` (number): The ID of this type
* `name` (string): The name of this type
* `type` (string): `marker` or `line`
* `defaultColour`, `defaultSize`, `defaultSymbol`, `defaultWidth`, `defaultMode` (string/number): Default values for the
different object properties
* `colourFixed`, `sizeFixed`, `symbolFixed`, `shapeFixed`, `widthFixed`, `modeFixed` (boolean): Whether those values are fixed and
cannot be changed for an individual object
* `fields` ([object]): The form fields for this type. Each field has the following properties:
* `name` (string): The name of the field. This is at the same time the key in the `data` properties of markers and lines
* `oldName` (string): When renaming a field (using [`editType(data)`](./methods#edittype-data)), specify the former name here
* `type` (string): The type of field, one of `textarea`, `dropdown`, `checkbox`, `input`
* `controlColour`, `controlSize`, `controlSymbol`, `controlShape`, `controlWidth` (boolean): If this field is a dropdown, whether
the different options set a specific property on the object
* `default` (string/boolean): The default value of this field
* `options` ([object]): If this field is a dropdown, an array of objects with the following properties:
* `value` (string): The value of this option.
* `oldValue` (string): When renaming a dropdown option (using [`editType(data)`](./methods#edittype-data)), specify the
former value here
* `colour`, `size`, `shape`, `symbol`, `width` (string/number): The property value if this field controls that property
## searchResult
* `short_name` (string): Name of the result
* `display_name` (string): Name with address
* `address` (string): Only the address
* `boundingbox` ([bbox](#bbox)): bbox that has a good view onto the result. Might be null if `zoom` is set.
* `lat`, `lon` (number): Position of the search result.
* `zoom` (number): Zoom level at which there is a good view onto the result. Might be null if `boundingbox` is set.
* `extratags` (object): Extra OSM tags that might be useful
* `geojson` (object): GeoJSON if the result has a shape
* `icon` (string): Symbol key of the result
* `type` (string): Type of the result
* `id` (string): If the result is an OSM object, the ID of the OSM object, prefixed by `n` (node), `w` (way) or `r` (relation)
* `ele` (number): Elevation in meters
## route
* `routePoints` (array): Array of route points (objects with `lon` and `lat` properties)
* `mode` (string): Route mode: `"car"`, `"bicycle"`, `"pedestrian"` or an empty string `""` for a direct line
* `trackPoints` (array): An array of track points (objects with a `lon`, `lat`, `ele`, `idx` property and also a `zoom`
property that indicates from which zoom level the track point should be shown (to avoid an unnecessarily high resolution))
* `distance` (number): The distance of the route in kilometers
* `time` (number): The time it takes to travel the route in seconds
* `ascent` (number): The total meters of climb
* `descent` (number) The total meters of drop

Wyświetl plik

@ -0,0 +1,13 @@
# Dev setup
1. Run `yarn install` to install the dependencies
2. Run `yarn build` to build the JS bundles
3. Copy `config.env.example` to `config.env` and adjust the settings
4. Run `yarn server` inside the `server` directory
For developing the frontend/client, FacilMap server can integrate webpack-dev-server. This server will automatically
recompile the frontend files when a file changes, and even delay reloads until the compilation has finished. To run
the dev server, run `yarn dev-server` instead of `yarn server` in the `server` directory. Note that changes in the `client`, `types` or `leaflet` directory still have to be built using `yarn build` in the respective directories for the dev-server to notice them.
To enable debug output of various components, additionally prepend the command by `DEBUG=*`. See the documentation of
[debug](https://github.com/visionmedia/debug). To only enable the debug logging of SQL queries, use `DEBUG=sql`.

Wyświetl plik

@ -19,7 +19,7 @@ In addition, FacilMap allows you to create collaborative maps, where you and oth
* By default, markers/lines/routes have a name and a description. You can [define additional fields](./types/) that contain more detailed information and can automatically influence the style of the marker/line/route.
* [Add a legend](./legend/) that shows which colour/style belongs to which type of marker/line.
* [Saved views](./views/) reference a particular area on the map with certain settings. You can change the default view of a collaborative map or save additional views as a shortcut for users to navigate to a certain area on the map.
* [Filters](./filters/) make it possible to temporarily hide certain types of markers/lines based on certain criteria.
* [Filters](./filter/) make it possible to temporarily hide certain types of markers/lines based on certain criteria.
* Modifications to the map are logged in the [edit history](./history/) and can be reverted if necessary.
* [Export](./export/) the map or parts of it as a GPX or GeoJSON file or as a table.
* [Import](./import/) GPX, KML or GeoJSON files. Importing a GeoJSON file that was exported by FacilMap makes it possible to copy parts of one map onto another.

Wyświetl plik

@ -2,7 +2,7 @@
A collaborative map is a map that can be reached under its own unique URL. Users can add markers, lines, routes and various other things to the map, and if multiple people are working on it simultaneously, they all see each others changes instantly. Think of it like an [Etherpad](https://etherpad.org/), just for maps.
While using a collaborative map, users can still use all of the non-collaborative features of FacilMap, such as [searching for a place](../search/), [calculating a route](../route/), [adding a map point](../click-marker/) etc. However, only [markers](../markers/) and [lines](../lines/) explicitly added to the map will be saved as part of it and be visible to other users. If you search for a place or calculate a route on a collaborative map, you might see the search results or the route on top of the markers and lines of the map (until you close the search or the route again), but others can still only see the markers and lines of the map. Also, if you move the map around, choose a different [map styles](../layers/) or enable a [filter](../filters/), this will not effect what other users are seeing, unless you save it as a [view](../views/) that other users can open.
While using a collaborative map, users can still use all of the non-collaborative features of FacilMap, such as [searching for a place](../search/), [calculating a route](../route/), [adding a map point](../click-marker/) etc. However, only [markers](../markers/) and [lines](../lines/) explicitly added to the map will be saved as part of it and be visible to other users. If you search for a place or calculate a route on a collaborative map, you might see the search results or the route on top of the markers and lines of the map (until you close the search or the route again), but others can still only see the markers and lines of the map. Also, if you move the map around, choose a different [map styles](../layers/) or enable a [filter](../filter/), this will not effect what other users are seeing, unless you save it as a [view](../views/) that other users can open.
When changing something on the map, there is no need to “Save” the map. Changes are applied immediately.
@ -30,7 +30,7 @@ When creating a collaborative map, some random characters are proposed for the d
| Add/edit/remove [custom types](../types/) | ✘ | ✘ | ✔ |
| Add/remove [views](../views/) | ✘ | ✘ | ✔ |
| Show [edit history](../history/) | ✘ | ✘ | ✔ |
| Change [map settings](../settings/) | ✘ | ✘ | ✔ |
| Change [map settings](../map-settings/) | ✘ | ✘ | ✔ |
| [Delete map](../map-settings/#delete-the-map) | ✘ | ✘ | ✔ |
## Exit a collaborative map

Wyświetl plik

@ -2,7 +2,7 @@
A map can be exported as a file, in order to use it in another application or to create a backup.
To export a map, in the [toolbox](../ui/#toolbox), click “Tools” and then one of the “Export” options. Note that when a [filter](../filters/) is active, only the objects that match the filter are exported.
To export a map, in the [toolbox](../ui/#toolbox), click “Tools” and then one of the “Export” options. Note that when a [filter](../filter/) is active, only the objects that match the filter are exported.
The exports are available under their own URL. In the context menu (right click) of the export links, you can copy the URL to use it elsewhere.

Wyświetl plik

@ -14,7 +14,7 @@ The following information is stored in the location hash:
* The [map point](../click-marker/)
* The selected [marker](../markers/) or [line](../lines/) (on [collaborative maps](../collaborative/))
* The active [view](../views/) (on [collaborative maps](../collaborative/))
* The active [filter](../filters/) (on [collaborative maps](../collaborative/))
* The active [filter](../filter/) (on [collaborative maps](../collaborative/))
## Technical details
@ -39,4 +39,4 @@ The different components of the long format have the following meaning:
* The ID of a [view](../views/) in the form `v123` (on [collaborative maps](../collaborative/)). This only works in the short format of the location hash.
* The ID of an OpenStreetMap object in the form `node 123`, `way 123`, `relation 123` or `trace 123`.
* Anything else that can be typed into the [search form](../search/).
* **filter:** The currently applied [filter](../filters/) (on [collaborative maps](../collaborative/))
* **filter:** The currently applied [filter](../filter/) (on [collaborative maps](../collaborative/))

Wyświetl plik

@ -1,6 +1,6 @@
# Legend
A legend describes the meaning of the different styles of items. FacilMap [shows the legend](../ui/#legend) as a box in the bottom right of the screen on big screens and as a [search box](../ui/#search-box) tab on small screens. The legend is shown if [custom legend text](#show-custom-text) is defined or if at least one type is configured to be [shown in the legend](#show-custom-types).
A legend describes the meaning of the different styles of items. FacilMap shows the legend as a box in the bottom right of the screen on big screens and as a [search box](../ui/#search-box) tab on small screens. The legend is shown if [custom legend text](#show-custom-text) is defined or if at least one type is configured to be [shown in the legend](#show-custom-types).
![](./example.png)

Wyświetl plik

@ -42,7 +42,7 @@ When you click on a line, it is highlighted and a [search box](../ui/#search-box
To edit the details of a line, select the line and then click “Edit data” in its [search box](../ui/#search-box) tab. A dialog will open where you can edit the following fields:
* **Name:** The name of the line. Will be shown as the heading in the line details and as a tooltip when hovering the line.
* **Routing mode:** The route mode of the line. By default, “straight line” is selected, but you can select something else to make the line points into route destinations. More information about route modes can be found under [routes](../routes/#route-modes).
* **Routing mode:** The route mode of the line. By default, “straight line” is selected, but you can select something else to make the line points into route destinations. More information about route modes can be found under [routes](../route/#route-modes).
* **Colour:** The colour of the line.
* **Width:** The width of the line (in pixels). Use the + and &minus; buttons to change the value.
* **Description:** The description of the line. Will be shown in the line details. You can format the text using [Markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
@ -53,7 +53,7 @@ Click “Save” to save your changes.
## Edit line points
To change the course or the position of a line, select the line and then click “Edit waypoints” in its [search box](../ui/#search-box) tab. A message will appear on the top right of the screen and the tab will turn into a search form and the line will become draggable. You can now change the line in the same way that you would [change a route](../routes/#drag-a-route), by changing the route destinations in the form or by dragging the line. When you are finished, click the “Finish” button in the message.
To change the course or the position of a line, select the line and then click “Edit waypoints” in its [search box](../ui/#search-box) tab. A message will appear on the top right of the screen and the tab will turn into a search form and the line will become draggable. You can now change the line in the same way that you would [change a route](../route/#drag-a-route), by changing the route destinations in the form or by dragging the line. When you are finished, click the “Finish” button in the message.
<Screencast :desktop="require('./drag.mp4')" :mobile="require('./drag-mobile.mp4')"></Screencast>

Wyświetl plik

@ -4,7 +4,7 @@ By default, a collaborative map has two object types, “Marker” and “Line
* You can give your types a custom name, you can customise what users see in the “Add” menu of the toolbox.
* You can define form fields in addition or in place of the description field, for example “Address”, “E-mail” or “Status”.
* You can preconfigure the initial style or make the style fixed. The style can also be configured to be dependent on a form field. For example, you can configure that the colour depends on the value of the “Status” field.
* You can easily show/hide objects of a particular type using [filters](../filters/).
* You can easily show/hide objects of a particular type using [filters](../filter/).
## Add a custom type
@ -90,4 +90,4 @@ Note that objects keep their data internally when you change the type to one tha
## Delete a type
Deleting a type is only possible if no objects of this type exist. If you want to delete a type that has existing objects, you might want to use a [filter](../filters) to identify them and then either delete them or change their type.
Deleting a type is only possible if no objects of this type exist. If you want to delete a type that has existing objects, you might want to use a [filter](../filter) to identify them and then either delete them or change their type.

Wyświetl plik

@ -1,12 +1,12 @@
# Saved views
Saved views represent a particular section of the map with a certain [map style](../layers/) and optionally a [filter](../filters/) active. Users can open a view by using the “Views” menu in the [toolbox](../ui/#toolbox) or by opening a [shared link](#share-a-link) to a view. A map can have a [default view](#default-view) that is initially loaded when users open the map.
Saved views represent a particular section of the map with a certain [map style](../layers/) and optionally a [filter](../filter/) active. Users can open a view by using the “Views” menu in the [toolbox](../ui/#toolbox) or by opening a [shared link](#share-a-link) to a view. A map can have a [default view](#default-view) that is initially loaded when users open the map.
## Save a view
To save a view, you must have the map open through its [admin link](../collaborative/#urls). In the [toolbox](../ui/#toolbox), click “Views” and then “Save current view”.
The view will persist the section of the map that you are currently viewing and the [map style](../layers/) (base layers and overlays) that is currently active. If a [filter](../filters) is currently active, you have the option to include that filter as part of the view or not.
The view will persist the section of the map that you are currently viewing and the [map style](../layers/) (base layers and overlays) that is currently active. If a [filter](../filter) is currently active, you have the option to include that filter as part of the view or not.
Saving a view does not directly affect any other users who are looking at the map. Views have to be manually opened, or, in case of the [default view](#default-view), are opened when the user initially opens a map.

Wyświetl plik

@ -1,49 +0,0 @@
Embedding FacilMap into a website
=================================
Using an iframe
---------------
It is perfectly fine to embed a map from [facilmap.org](https://facilmap.org/) into an iframe.
```html
<iframe style="height: 500px; width: 100%; border: none;" src="https://facilmap.org/mymap"></iframe>
```
If you use a map ID that does not exist yet, the “Create Collaborative Map” dialog will be opened when accessing the
map.
You can control the display of different components by using the following query parameters:
* `toolbox`: Show the toolbox (default: `true`)
* `search`: Show the search bar (default: `true`)
* `autofocus`: Autofocus the search field (default: `false`)
* `legend`: Show the legend if available (default: `true`)
* `interactive`: Show certain items (“Create collaborative map”, “Open file”) in the toolbox (default: `false`)
Example:
```html
<iframe style="height: 500px; width: 100%; border: none;" src="https://facilmap.org/mymap?search=false&amp;toolbox=false"></iframe>
```
To synchronize the map state with the location hash (to add something like #9/31/24 to the address bar of the browser to indicate the current map view), add the following script:
```html
<iframe id="facilmap" style="height: 500px; width: 100%; border: none;" src="https://facilmap.org/mymap"></iframe>
<script>
window.addEventListener("message", function(evt) {
if(evt.data && evt.data.type == "facilmap-hash" && location.hash != "#" + evt.data.hash)
location.replace("#" + evt.data.hash);
});
function handleHashChange() {
var iframe = document.getElementById("facilmap");
iframe.src = iframe.src.replace(/(#.*)?$/, "") + location.hash;
}
window.addEventListener("hashchange", handleHashChange);
if (location.hash)
handleHashChange();
</script>
```

Wyświetl plik

@ -1,96 +1,5 @@
Running the FacilMap server
===========================
**facilmap-server** is the Node.js server for [FacilMap](https://github.com/facilmap/facilmap).
Using docker
------------
Information how to run the server can be found in the [administrator documentation](https://docs.facilmap.org/administrators/server.html).
FacilMap is available as [`facilmap/facilmap`](https://hub.docker.com/r/facilmap/facilmap/) on Docker Hub. Here is
an example `docker-compose.yml`:
```yaml
version: "2"
services:
facilmap:
image: facilmap/facilmap
ports:
- 8080
links:
- db
environment:
USER_AGENT: My FacilMap (https://facilmap.example.org/, facilmap@example.org)
DB_TYPE: mysql
DB_HOST: db
DB_NAME: facilmap
DB_USER: facilmap
DB_PASSWORD: password
OSR_TOKEN: # Get an API key on https://go.openrouteservice.org/ (needed for routing)
MAPBOX_TOKEN: # Get an API key on https://www.mapbox.com/signup/ (needed for routing)
MAPZEN_TOKEN: # Get an API key on https://mapzen.com/developers/sign_up (needed for elevation info)
MAXMIND_USER_ID: # Sign up here https://www.maxmind.com/en/geolite2/signup (needed for geoip lookup to show initial map state)
MAXMIND_LICENSE_KEY:
restart: on-failure
db:
image: mariadb
environment:
MYSQL_DATABASE: facilmap
MYSQL_USER: facilmap
MYSQL_PASSWORD: password
MYSQL_RANDOM_ROOT_PASSWORD: "true"
```
Or the same using `docker create`:
```bash
docker create --link=mysql_mysql_1 -p 8080 --name=facilmap -e "USER_AGENT=My FacilMap (https://facilmap.example.org/, facilmap@example.org)" -e DB_TYPE=mysql -e DB_HOST=mysql_mysql_1 -e DB_NAME=facilmap -e DB_USER=facilmap -e DB_PASSWORD=facilmap -e OSR_TOKEN= -e MAPBOX_TOKEN= -e MAPZEN_TOKEN= --restart on-failure facilmap/facilmap
```
See [below](#config) for the available config options.
Both the FacilMap server and the frontend will be available via HTTP on port `8080`. It is recommended to use a reverse
proxy, such as [`jwilder/nginx-proxy`](https://hub.docker.com/r/jwilder/nginx-proxy), to make it available over HTTPS.
Standalone
----------
To run the FacilMap server by hand, follow the following steps:
1. Make sure that you have a recent version of [Node.js](https://nodejs.org/), [yarn](https://yarnpkg.com/)
and a database (MariaDB, MySQL, PostgreSQL, SQLite, Microsoft SQL Server) set up. (Note that only MySQL/MariaDB has been tested so far.)
2. Clone this repository.
3. Run `yarn install` in the root folder of this repository to install the dependencies.
4. Run `yarn build` to create the JS bundles
5. Copy `config.env.example` to `config.env` and adjust the configuration (see [below](#config) for the available options).
6. Inside the `server` directory, run `yarn server`. This will automatically set up the database structure and start the server.
Config
------
The config can be set either by using environment variables (useful for docker) or by editing [`config.env`](../config.env).
| Variable | Meaning |
|-----------------------|----------------------------------------------------------------------------------------------------------------------------------|
| `USER_AGENT` | Will be used for all HTTP requests (search, routing, GPX/KML/OSM/GeoJSON files). You better provide your e-mail address in here. |
| `HOST` | The ip address to listen on (leave empty to listen on all addresses) |
| `PORT` | The port to listen on. |
| `DB_TYPE` | The type of database. Either `mysql`, `postgres`, `mariadb`, `sqlite`, or `mssql`. |
| `DB_HOST` | The host name of the database server (default: `localhost`). |
| `DB_PORT` | The port of the database server (optional). |
| `DB_NAME` | The name of the database (default: `facilmap`). |
| `DB_USER` | The username to connect to the database with (default: `facilmap`). |
| `DB_PASSWORD` | The password to connect to the database with. |
| `ORS_TOKEN` | OpenRouteService API key. |
| `MAPBOX_TOKEN` | Mapbox API key. |
| `MAPZEN_TOKEN` | Mapzen API key. |
| `MAXMIND_USER_ID` | MaxMind user ID. |
| `MAXMIND_LICENSE_KEY` | MaxMind license key. |
Development
-----------
For developing the frontend/client, FacilMap server can integrate a webpack-dev-server. This server will automatically
recompile the frontend files when a file changes, and even delay reloads until the compilation has finished. To run
the dev server, run `yarn dev-server` instead of `yarn server` in the `server` directory.
To enable debug output of various components, additionally prepend the command by `DEBUG=*`. See the documentation of
[debug](https://github.com/visionmedia/debug). To only enable the debug logging of SQL queries, use `DEBUG=sql`.
Information how to setup a dev environment can be found in the [developer documentation](https://docs.facilmap.org/developers/development/dev-setup.html).