A project to display the DnD westmarches world of Jorm using the LeafletJS library.
Though made specifically for the world of Jorm, it can easily be reused for any other world by editing the locations.json file. Likewise to add/edit existing locations just edit the locations.json file. (Fork and pull request or ask to become a contributor to directly push changes)
Locations specified with markers in the Locations.json file can be shared by specifying both a plane=
and a location=
url parameter. Alternatively any location can be shared by specifying its latitude and longitude with both the lat=
and lng=
url parameters. Additionally there zoom=
url parameter can be specified to share a location at a specific zoom level (LeafletJS zoom levels, meaning 0 is zoomed out and 20 is zoomed in).
Example
http://localhost:8000/?plane=Jorm&location=Dod%27Estrin
http://localhost:8000/?plane=Jorm&location=Dod%27Estrin&zoom=5
http://localhost:8000/?lat=2815360.8285000003&lng=3152704.8960000006
http://localhost:8000/?lat=2815360.8285000003&lng=3152704.8960000006&zoom=5
When trying to open the index.html after cloning you'll notice that it won't load correctly, this is due to the fact that you can't use a fetch()
, which is used to load locations.json, on local files (Cross-Origin Request Blocked). So in order to test the page and anything on it you'll have to run an http server and open that in your browser instead, for example with python you can run py -m http.server
in your working directory and it'll be available on http://localhost:8000 by default.
The JSON file which is used to load all marker and image data.
The base of Locations.json is made of key-value pairs for Planes.
{
"Jorm": {...},
"Shadowfell": {...},
...
}
A Plane is made of key-value pairs for Places.
"Plane": {
"Dod'Estrin": {...},
"Wizard Tower": {...},
...
}
A Place has 3 optional objects: image
, images
, marker
. Where images
will be ignored if an image
object has also been supplied.
"Place 1": {
"images": {...},
"marker": {...}
},
"Place 2": {
"image": {...}
}
An Images object is made of key-value pairs for Image objects where the key is the floor at which the image is located.
"images": {
"-5": {...},
"0": {...},
"3": {...},
...
}
An Image has a required meta
object containing meta data about where the image is located and optionally options that are passed to the leaflet constructor for the image. By default if not set an image will have the option pane
set to "tilePane" which adds all generated html elements to the same container div.
"image": {
"meta": {...},
"opacity": 1,
...
}
Image metadata has 3 required objects: position
, layers
, file
. Where file
is a string which is the link to the image to be shown, if the image is local then it'll be found relative to the images folder.
"meta": {
"position": {...},
"file": "DodEstrin.jpg",
"layers": {...}
}
An image position has an optional rotation
which is how many degrees the image will be rotated and a required boundaries representation which can be either bounds
, which is a 2 long array of latlng's which define the top-left latlng and bottom-right latlng of the boundaries, or a combination of a width
length, a height
length, and either a center
location or topleft
latlng (if both are defined the center
will take precedent).
"position": {
"bounds": [[33, 33], [44, 44]]
}
//
"position": {
"rotation": 33,
"width": {...},
"height": {...},
"center": {...}
}
//
"position": {
"width": {...},
"height": {...},
"topleft": {...}
}
A Marker has a required meta
object containing meta data about where the marker is located and optionally options that are passed to the leaflet constructor for the marker.
"marker": {
"meta": {...},
"attribution": "A brain",
...
}
Marker metadata has an optional object click
and 2 required objects: location
, layers
.
"meta": {
"location": {...},
"click": {...},
"layers": {...}
}
A Click object has an optional jump_zoom
number which specifies what at zoomlevel will be zoomed to when the marker is clicked. (Currently that's the only click option but it's an object for future possible additional options)
"click": {
"jump_zoom": 13
}
Layers has 2 required numbers min
, max
which define the range from what layer until what layer (inclusive) the marker/image is visible.
"layers": {
"min": 13,
"max": 19
}
A Location is an object that resolves to a latlng which can be using one of 3 ways: 1. latlng
, 2. origin
and offset
, 3. origin
, distance
length, and direction
. They have precedence in that order and are all required for their respective ways.
//1
"location": {
"latlng": [200, 30]
}
//2
"location": {
"origin": {...},
"offset": {...}
}
//3
"location": {
"origin": {...},
"direction": {...},
"distance": {...}
}
A Latlng is a number array of 2 numbers representing a Latitude and Longitude, in that order.
"latlng": [42, 420]
A Length is a representation of a distance, either by specifying the length itself, via meter
, feet
, tiles
, kilometers
, and mile
, or by specifying a duration
. (Taking precedence in that order)
"length": {
"meter": 10
}
//...
"length": {
"duration": {...}
}
A Duration is a distance as specified by the travel duration in a number days
, number hours
, or special hour_timestamp
. Assuming a travel speed of 3 mile/hour or 24 miles per day (As per the Travel Pace table in the 5e PHB).
//10 and a half days of travel
"duration": {
"days": 10.5
}
//4 and a half hours of travel
"duration": {
"hours": 4.5
}
//1 hour and 20 minutes of travel
"duration": {
"hour_timestamp": "1:20"
}
An Origin is a relative point of reference which resolves to a latlng using either latlng
or a location
which is the name of a Place (specifically the place's marker will be used for getting its location, so if it doesn't have a marker it cannot be used as an origin) with optionally a Plane's name to specify what plane that place is on if it's not on the same Plane the currently being assigned to location is.
"origin": {
"latlng": [60, 90]
}
//
"origin": {
"location": "Dod'Estrin",
"plane": "Jorm"
}
An Offset has a lat
Length and a lng
Length which specify how far offset from the origin the latitude and longitude will be.
"offset": {
"lat": {...},
"lng": {...}
}
A Direction has an angle in degrees
, radians
, or a compass
string. (Presedence in that order).
"direction": {
"degrees": 50.41
}
//
"direction": {
"radians": 2.1
}
//
"direction": {
"compass": "SSW"
}