Interactive, editable personal web map for Civ-style Minecraft servers
Used for CivClassic, DevotedMC 3.0, CivEx.
The custom map tiles (height, biome, landmasses, night) are created with a different project.
info
:{ "version": "3.0.0-beta3", "last_update": 1553379758 }
version
: must be set to current version ("3.0.0-beta3"
) to allow converting to future versionslast_update
: unix timestamp (seconds), optional
name
: displayed in the layer selector menufeatures
: array of feature objects, optionalpresentations
: array of presentation objects, optionalenabled_presentation
: presentation name that will be shown when collection is loaded, if unset defaults to first presentation
A typical feature looks like this:
{
"id": "e767a0bc-9df0-4ec1-87b7-f5cb528bb38b", // must be globally unique
"name": "Mount Augusta", // displayed in sidebar, typically styles use this as label
"x": -6700, "z": 3000, // or "line", "polygon", etc. - see below
"image": "https://example.com/MtA-Render.png", // shows up in the sidebar
"web": "/r/MtAugusta" // arbitrary properties are ok, "/r/" etc. get rendered as clickable link
}
id
must be globally unique. CivMap uses UUIDs internally but this can be any text (e.g. namespaced: "com.github.gjum.civclassic.railmap.stations.westminster"
).
They are needed for updating old features with new info and referring from one feature to another.
polygon, line, x, z, radius, map_image
represent the feature's geometry on the map.
Any feature can have any combination of these, the chosen geometry is currently prioritized image > polygon > line > circle > marker
. In a future version, the geometry with the biggest surface at the current zoom level will be displayed (marker when zoomed out so the feature only covers a few pixels, polygon/line/circle/image when zoomed in).
{ "map_image": { "bounds": [[w,n],[e,s]], "url": "https://example.com/overlay.png" } }
wherew/n/e/s
are west/north/east/south. Accepts PNG, JPG, SVG (but avoid SVGs covering large areas, currently they lag some browsers when zoomed in){ "polygon": [ [ [x1,z1], [x2,z2], … ], [optional: holes or more polygon parts], … ] }
The polygon will be closed automatically, you do not need to duplicate the first/last point.{ "line": [ [ [x1,z1], [x2,z2], … ], [optional: more line parts], … ] }
- polygons/lines also allow a string like
"(((x1,z1!x2,z2!…)),…)"
instead (more compact, used in export URLs) - circle:
{ "x": 123, "z": -321, "radius": 456 }
- point:
{ "x": 123, "z": -321 }
All coordinates are centered on the center of a block, except image bounds which align with a block's NW corner.
name
and image
are also special:
name
: shown in sidebar selecion menues, distinguishes between all features, ex:Westminster Rail Station
image
: direct URL, shown in Feature Details
The "presentation" lets you control the style attributes of the features.
style_base
is the same for all features in the collection- one of the
zoom_styles
is applied to all features according to the current zoom level (see example below) style_highlight
is only applied to highlighted features (selection, search results, ...)
The overriding order is: combinedStyle = { ...baseStyle, ...zoomStyle, ...highlightStyle }
The result will be passed through this function and then applied to the leaflet element (code).
label
(default$name
)opacity
(fill and stroke; 0 means the feature is invisible)fill_opacity
color
(fill and stroke)hue
([0..360]
; overrides color if set)stroke_color
stroke_width
dash_array
icon_size
icon
(URL; a circle by default)
More details on marker icon styles in the code
{ // ... other collection properties omitted ...
"presentations": [
// there can be none (=default styles), one, or several presentations
// if there's several, the sidebar lets the user select which one to use for this collection
{
"name": "Rails and Stops", // when there's more than one presentation, this name will show up in the sidebar
"style_base": {
"color": "#ffffff", // primitives are applied to all features
// $-prefixed feature keys resolve to the value of that feature property
// | separates a fallback value: style = feature[key] || fallback
// this will be fixed to use undefined/NaN check, to allow 0, '', and false as values
"label": "$nice_name|(unnamed)",
// objects specify how to compute the style from the feature props
"stroke_color": {
// category selectors are like a switch-case statement
// for each feature, its "stroke_color" style depends on the feature's "elevation" property
"feature_key": "elevation",
"categories": {
"underground": "#00ff00",
"surface": "#00ffff",
// the value can also be another nested selector
"elevated": {
"feature_key": "elevation_type",
"categories": {
"skylimit": "#123123",
"viaduct": "#345345"
},
"default": "#234234"
}
},
"default": "#808080"
},
"stroke_width": {
// range selectors linearly map the value of a feature property to a style value, interpolating/extrapolating appropriately
// implementation: https://github.com/Gjum/CivMap/blob/master/app/js/utils/presentation.js#L50
"feature_key": "num_tracks",
"range": {
"min_in": 1, "max_in": 5, // in feature units
"min_out": 2, "max_out": 10 // in style units (here: px)
}
}
},
"zoom_styles": {
// searched in ascending order for the largest key that is smaller than or equal to the current zoom
"-6": { // zoomed out all the way
// each zoom entry is structured exactly the same as style_base
"opacity": {
// example: only features with "importance":"major" are visible when zoomed out
"feature_key": "importance",
"categories": {
"major": 1
},
"default": 0
}
},
"0": { // zoomed in at 1 block to 1 pixel
"opacity": 1 // now all features are visible
}
},
// style_highlight is structured exactly the same as style_base,
// but applied to selected/highlighted features in addition to style_base
"style_highlight": {
"stroke_color": "#ff0000"
}
}
]
}
Currently, the library exposes a Redux Store as window.CivMap.api
.
Some examples:
console.log(CivMap.api.getState())
returns a read-only snapshot of the whole application data store:
{
collections: {civmap:collection/user: {…}, /data/settlements.civmap.json: {…}},
control: {appMode: "LAYERS", searchQuery: null, activeFeatureId: "e767a0bc-9df0-4ec1-87b7-f5cb528bb38b", …},
mapView: {basemapId: "simple", viewport: {x: -123, z: 321, radius: 4321}},
// ...
}
Do not change anything directly, but reading from it is fine.
To change something, use CivMap.api.dispatch(…)
.
For example, to add/update a feature:
CivMap.api.dispatch({
type: "UPDATE_FEATURE_IN_COLLECTION",
collectionId: "civmap:collection/user",
feature: {
id: "e767a0bc-9df0-4ec1-87b7-f5cb528bb38b",
name: "My Test Feature",
x: 0, z: 0
}
})
For now, the action constants and parameters may change any time, and can only be found in the source code (app/js/store.js
).
After cloning the repository, install the dependencies:
npm install
Now you can run the local development web server:
npm start
Open the map on http://localhost:8080
Update the version info in package.json
, create a new tag, and push it to the repository.
Clone your gh-pages
branch to dist/
:
git clone --single-branch -b gh-pages git@github.com:YOUR-GITHUB-ACCOUNT/CivMap.git dist/
Generate dist/js/bundle.js
and the other assets:
npm run build
Push dist/
to gh-pages
:
cd dist/
git commit -a -m "Release v$version"