diff --git a/custom-tilemaker/config.json b/custom-tilemaker/config.json
index 534f97c..778b97b 100644
--- a/custom-tilemaker/config.json
+++ b/custom-tilemaker/config.json
@@ -16,7 +16,7 @@
"high_resolution": true,
"name": "Tilemaker golfTiles schema",
"version": "0.1",
- "description": "Tiles for features inside of golf_courses ",
+ "description": "Tiles for features inside of golf_course facilities",
"compress": "gzip"
},
"metadata": {
diff --git a/custom-tilemaker/process.lua b/custom-tilemaker/process.lua
index d0d15b5..601cc35 100644
--- a/custom-tilemaker/process.lua
+++ b/custom-tilemaker/process.lua
@@ -121,6 +121,43 @@ local function set_AttributeInteger_or_Attribute(attributenkey, value)
end
end
+local function hsl_to_rgb(h, s, l)
+ local c = (1 - math.abs(2*l - 1)) * s
+ local x = c * (1 - math.abs((h / 60) % 2 - 1))
+ local m = l - c/2
+
+ local r, g, b = 0, 0, 0
+
+ if h < 60 then r, g, b = c, x, 0
+ elseif h < 120 then r, g, b = x, c, 0
+ elseif h < 180 then r, g, b = 0, c, x
+ elseif h < 240 then r, g, b = 0, x, c
+ elseif h < 300 then r, g, b = x, 0, c
+ else r, g, b = c, 0, x end
+
+ return
+ math.floor((r + m) * 255),
+ math.floor((g + m) * 255),
+ math.floor((b + m) * 255)
+end
+
+-- Function to convert a name of a course into a color.
+-- Requires lua 5.3 to be able to use the bitwise XOR tilde ~
+local function string_to_color(str)
+
+ --Uses FNV-1a:
+ local hash = 2166136261 -- FNV offset basis
+ for i = 1, #str do
+ hash = hash ~ string.byte(str, i)
+ hash = (hash * 16777619) % 2^32
+ end
+ local hue = hash % 360 -- The hue is a value in between 0-360.
+ local r, g, b = hsl_to_rgb(hue, 0.65, 0.55)
+
+ return string.format("#%02x%02x%02x", r, g, b)
+
+end
+
-- Nodes will only be processed if one of these keys is present. This reduces memory drastically as stated by the documentation.
node_keys = { "golf", "tee", "natural", "leaf_cycle", "leaf_type", "information", "amenity", "vending",
@@ -396,6 +433,9 @@ function way_function()
-- Still sets the course info from the golf=holes even if no route=golf tags is present.
if golf_course_name ~= "" and not set_golf_course_name then
Attribute("golf:course:name", golf_course_name) -- Name of the course this hole belongs to.
+
+ Attribute("course_name_color", string_to_color(golf_course_name))
+ -- the Maplibre GL style to use for golf=hole lines and other coloring to to lack of proper scripting support in the style itself.
end
if golf_course ~= "" and not set_golf_course then
Attribute("golf:course", golf_course)
@@ -539,7 +579,7 @@ function way_function()
-- Rivers
local waterway = Find("waterway")
- if waterway == "stream" or waterway == "river" or waterway == "canal" then -- Is this to restrictive? Maybe more?
+ if waterway ~= "" then
Layer("golf_lines", false)
Attribute("waterway", waterway)
-- "General" common "extra" attributes between nodes & ways/areas:
diff --git a/index.html b/index.html
index eb6c2c3..dbd6675 100644
--- a/index.html
+++ b/index.html
@@ -6,9 +6,9 @@
-
+
-
+
@@ -44,10 +44,26 @@ Initial Demo using Maplibre GL JS over Sweden, finland and Denmark:
p.getHeader().then(h => {
const map = new maplibregl.Map({
container: 'map',
- zoom: h.maxZoom - 2, // golfTiles is rendered at max zoom of 14.
+ zoom: h.maxZoom - 1, // golfTiles is rendered at max zoom of 14.
center: [15.59411, 56.52839], //Centers on Emmaboda GK.
- style: 'https://golftiles.org/styles/golfTilesStyle.json'
+ pitch: 70,
+ style: 'styles/golfTilesStyle.json', // relative: resolves to golftiles.org in production and to the local copy when serving the repo root during development.
+ maxPitch: 85
});
+ map.addControl(
+ new maplibregl.NavigationControl({
+ visualizePitch: true,
+ showZoom: true,
+ showCompass: true
+ })
+ );
+
+ map.addControl(
+ new maplibregl.TerrainControl({
+ source: 'terrainSource',
+ exaggeration: 1
+ })
+ );
});
diff --git a/styles/golfTilesStyle.json b/styles/golfTilesStyle.json
index 66c7cf4..c13c5a8 100644
--- a/styles/golfTilesStyle.json
+++ b/styles/golfTilesStyle.json
@@ -6,11 +6,68 @@
"type": "vector",
"url": "pmtiles://https://golftiles.org/samples/golfTiles_se_dk_fi.pmtiles",
"attribution": "© OpenStreetMap . Schema and style golfTiles "
- }
+ },
+ "terrainSource": {
+ "type": "raster-dem",
+ "url": "https://tiles.mapterhorn.com/tilejson.json"
+ }
},
+ "glyphs": "https://huggek.github.io/golfTiles/fonts/{fontstack}/{range}.pbf",
"layers": [
{
- "id": "ranges",
+ "id": "Facilities base layer",
+ "source": "golfTiles_source",
+ "source-layer": "facilities",
+ "type": "fill",
+ "paint": {
+ "fill-color": "#51aa60"
+ }
+ },
+ {
+ "id": "Tourism campsite",
+ "source": "golfTiles_source",
+ "source-layer": "other_areas",
+ "type": "fill",
+ "filter": [
+ "all",
+ ["==", ["get", "tourism"], "camp_site"]
+ ],
+ "paint": {
+ "fill-color": "#22a6aa"
+ }
+ },
+ {
+ "id": "Lakes and rivers",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "type": "fill",
+ "filter": [
+ "match",
+ ["get", "water"],
+ ["lake", "river"], true,
+ false
+ ],
+ "paint": {
+ "fill-color": "#184565"
+ }
+ },
+ {
+ "id": "Streams and Rivers",
+ "source": "golfTiles_source",
+ "source-layer": "golf_lines",
+ "type": "line",
+ "filter": [
+ "has",
+ "waterway"
+ ],
+ "paint": {
+ "line-color": "#184565"
+ }
+ },
+
+
+ {
+ "id": "Ranges",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -23,7 +80,26 @@
}
},
{
- "id": "roughs",
+ "id": "Ranges text on borders",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "filter": [
+ "all",
+ ["==", ["get", "golf"], "driving_range"]
+ ],
+ "type": "symbol",
+ "layout": {
+ "text-field": "Driving Range",
+ "text-font": ["Open Sans Regular"],
+ "text-size": 14,
+ "text-variable-anchor": ["top", "bottom", "center", "left", "right"]
+ },
+ "paint": {
+ "text-color": "#000000"
+ }
+ },
+ {
+ "id": "Roughs",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -36,7 +112,7 @@
}
},
{
- "id": "fairways",
+ "id": "Fairways",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -49,7 +125,20 @@
}
},
{
- "id": "bunkers",
+ "id": "Waste areas",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "type": "fill",
+ "filter": [
+ "all",
+ ["==", ["get", "natural"], "sand"]
+ ],
+ "paint": {
+ "fill-color": "#b5998d"
+ }
+ },
+ {
+ "id": "Bunkers",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -62,7 +151,7 @@
}
},
{
- "id": "tees_areas",
+ "id": "Tees areas",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -75,11 +164,15 @@
}
},
{
- "id": "tees_borders",
+ "id": "Tees color borders",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "line",
- "filter": ["has", "tee"],
+ "filter": [
+ "==",
+ ["typeof", ["get", "tee"]],
+ "string"
+ ],
"paint": {
"line-color": [
"coalesce",
@@ -89,7 +182,28 @@
}
},
{
- "id": "greens",
+ "id": "Tees Numeric Borders",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "type": "symbol",
+ "filter": [
+ "==",
+ ["typeof", ["get", "tee"]],
+ "number"
+ ],
+ "layout": {
+ "text-field": ["to-string", ["get", "tee"]],
+ "text-font": ["Open Sans Regular"],
+ "text-size": 14,
+ "symbol-placement": "line",
+ "symbol-spacing": 250
+ },
+ "paint": {
+ "text-color": "#223631"
+ }
+ },
+ {
+ "id": "Greens",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -102,7 +216,7 @@
}
},
{
- "id": "trees_areas",
+ "id": "Trees Areas",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -115,7 +229,7 @@
}
},
{
- "id": "trees",
+ "id": "Trees",
"source": "golfTiles_source",
"source-layer": "golf_points",
"type": "circle",
@@ -124,12 +238,30 @@
["==", ["get", "natural"], "tree"]
],
"paint": {
- "circle-color": "#1a6b3c"
-
+ "circle-color": "#1a6b3c",
+ "circle-radius": [
+ "interpolate",
+ ["linear"],
+ ["zoom"],
+ 12, 1,
+ 13, 3,
+ 20, 4
+ ]
+ }
+ },
+ {
+ "id": "Facility Borders",
+ "source": "golfTiles_source",
+ "source-layer": "facilities",
+ "type": "line",
+ "paint": {
+ "line-color": "#223631",
+ "line-width": 2,
+ "line-opacity": 0.8
}
},
{
- "id": "penalty_areas",
+ "id": "Penalty areas",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "fill",
@@ -143,7 +275,7 @@
}
},
{
- "id": "penalty_areas_borders",
+ "id": "Penalty areas borders",
"source": "golfTiles_source",
"source-layer": "golf_areas",
"type": "line",
@@ -164,20 +296,20 @@
}
},
{
- "id": "out_of_bounds_lines",
+ "id": "Out of bounds lines",
"source": "golfTiles_source",
"source-layer": "golf_lines",
"type": "line",
"filter": [
"all",
- ["==", ["get", "golf"], "hole"]
+ ["==", ["get", "golf"], "out_of_bounds"]
],
"paint": {
"line-color": "#faf9f9"
}
},
{
- "id": "hole_lines",
+ "id": "Hole lines",
"source": "golfTiles_source",
"source-layer": "golf_lines",
"type": "line",
@@ -186,11 +318,92 @@
["==", ["get", "golf"], "hole"]
],
"paint": {
- "line-color": "#1a3002"
+ "line-color": [
+ "case",
+ ["has", "course_name_color"],
+ ["get", "course_name_color"],
+ "#cccccc"
+ ]
}
},
{
- "id": "golf_pins",
+ "id": "Hole number, par, index, name and course name text on lines",
+ "source": "golfTiles_source",
+ "source-layer": "golf_lines",
+ "type": "symbol",
+ "filter": [
+ "all",
+ ["==", ["get", "golf"], "hole"]
+ ],
+ "layout": {
+ "text-font": ["Open Sans Regular"],
+ "text-size": 14,
+ "symbol-placement": "line",
+ "symbol-spacing": 250,
+ "text-field": [
+ "concat",
+ [
+ "case",
+ ["has", "hole_number"],
+ [
+ "concat",
+ "Hole ",
+ ["coalesce", ["get", "hole_number"], ""],
+ ". "
+ ],
+ ""
+ ],
+ [
+ "case",
+ ["has", "par"],
+ [
+ "concat",
+ "Par ",
+ ["coalesce", ["get", "par"], ""],
+ ". "
+ ],
+ ""
+ ],
+ [
+ "case",
+ ["has", "handicap"],
+ [
+ "concat",
+ "Index ",
+ ["coalesce", ["get", "handicap"], ""],
+ ". "
+ ],
+ ""
+ ],
+ [
+ "case",
+ ["has", "name"],
+ [
+ "concat",
+ ["coalesce", ["get", "name"], ""],
+ ". "
+ ],
+ ""
+ ],
+ [
+ "case",
+ ["has", "golf:course:name"],
+ [
+ "concat",
+ "Course: ",
+ ["coalesce", ["get", "golf:course:name"], ""],
+ ". "
+ ],
+ ""
+ ]
+ ]
+ },
+ "paint": {
+ "text-color": "#223631"
+ }
+ },
+ {
+ "id": "Golf pins",
"source": "golfTiles_source",
"source-layer": "golf_points",
"type": "circle",
@@ -204,25 +417,127 @@
"interpolate",
["linear"],
["zoom"],
- 10, 2,
- 15, 2,
- 20, 2
+ 12, 1,
+ 13, 2,
+ 20, 3
]
}
},
{
- "id": "facility_borders",
+ "id": "Area:highway",
"source": "golfTiles_source",
- "source-layer": "facilities",
+ "source-layer": "golf_areas",
+ "type": "fill",
+ "filter": [
+ "has",
+ "area_highway"
+ ],
+ "paint": {
+ "fill-color": "#e6e6e6"
+ }
+ },
+ {
+ "id": "Parking lot",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "type": "fill",
+ "filter": [
+ "all",
+ ["==", ["get", "amenity"], "parking"]
+ ],
+ "paint": {
+ "fill-color": "#999999"
+ }
+ },
+ {
+ "id": "Golf Carthpaths",
+ "source": "golfTiles_source",
+ "source-layer": "golf_lines",
"type": "line",
+ "filter": [
+ "all",
+ ["==", ["get", "golf"], "cartpath"]
+ ],
"paint": {
- "line-color": "#223631",
+ "line-color": "#fa8173",
"line-width": 2,
- "line-opacity": 0.8
+ "line-dasharray": [2, 2]
}
},
{
- "id": "facility_text_on_borders",
+ "id": "Golf Paths",
+ "source": "golfTiles_source",
+ "source-layer": "golf_lines",
+ "type": "line",
+ "filter": [
+ "all",
+ ["==", ["get", "golf"], "path"],
+ ["==", ["get", "highway"], "path"]
+ ],
+ "paint": {
+ "line-color": "#e47569",
+ "line-width": 2,
+ "line-dasharray": [2, 2]
+ }
+ },
+ {
+ "id": "Highways",
+ "source": "golfTiles_source",
+ "source-layer": "golf_lines",
+ "type": "line",
+ "filter": [
+ "all",
+ ["has", "highway"],
+ ["!=", ["get", "highway"], "path"]
+ ],
+ "paint": {
+ "line-color": "#ffffff",
+ "line-width": 4
+ }
+ },
+ {
+ "id": "Golf Clubhouses",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "type": "fill",
+ "filter": [
+ "all",
+ ["==", ["get", "golf"], "clubhouse"]
+ ],
+ "paint": {
+ "fill-color": "#7c3be4"
+ }
+ },
+ {
+ "id": "Restaurants",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "type": "fill",
+ "filter": [
+ "all",
+ ["==", ["get", "amenity"], "restaurant"]
+ ],
+ "paint": {
+ "fill-color": "#cda7c6"
+ }
+ },
+ {
+ "id": "Buildings",
+ "source": "golfTiles_source",
+ "source-layer": "golf_areas",
+ "type": "fill",
+ "filter": [
+ "all",
+ ["has", "building"],
+ ["!=", ["get", "golf"], "clubhouse"],
+ ["!=", ["get", "amenity"], "restaurant"]
+ ],
+ "paint": {
+ "fill-color": "#ff8c75"
+ }
+ },
+ {
+ "id": "Facility text on borders",
"source": "golfTiles_source",
"source-layer": "facilities",
"type": "symbol",
@@ -238,7 +553,7 @@
}
},
{
- "id": "facility_text_midpoints",
+ "id": "Facility text center",
"source": "golfTiles_source",
"source-layer": "facilities",
"type": "symbol",
@@ -246,11 +561,17 @@
"text-field": ["get", "name"],
"text-font": ["Open Sans Regular"],
"text-size": 14,
- "text-variable-anchor": ["center", "top", "bottom", "left", "right"]
+ "text-variable-anchor": ["bottom", "center", "top", "left", "right"]
},
"paint": {
"text-color": "#000000"
}
}
- ]
-}
\ No newline at end of file
+ ],
+ "terrain": {
+ "source": "terrainSource",
+ "exaggeration": 1.5
+ },
+ "sky": {}
+
+}
diff --git a/styles/schema_and_style.md b/styles/schema_and_style.md
new file mode 100644
index 0000000..9843178
--- /dev/null
+++ b/styles/schema_and_style.md
@@ -0,0 +1,37 @@
+Due to the nature of Maplibre GL styles are in .json files which one cannot annotate with comments some explanations of the behavior of the style and schema follows down below: (Note that this will be reworked as a proper documentation on github pages in the future like Shortbread does it.)
+
+
+
+
+Note that ref= from OSM gets renamed to hole_number in the golfTiles schema.
+set_AttributeInteger_and_log("hole_number", ref) -- this is one of the few times a rename of the key in the tiles occur. More suitable with hole_number than generic ref.
+
+
+
+
+Only tees which are actual areas is rendered.
+The style also have a way to style the borders of tee´s if the key tee= is set to a valid html color. If it is a not valid html color, the border will fallback on the same color as the tee itself. Could also be a #HEX color. If a number is used it will be displayed as text atop the border. This is using the expression syntax in Maplibre GL style spec ["typeof"](https://maplibre.org/maplibre-style-spec/expressions/#typeof).
+
+
+
+
+Font glyphs are self-hosted on GitHub Pages: the style's top-level glyphs property points at
+https://huggek.github.io/golfTiles/fonts/{fontstack}/{range}.pbf and every symbol layer uses the
+"Open Sans Regular" fontstack. The .pbf glyph ranges live in docs/fonts/ in this repository
+(prebuilt ranges from the openmaptiles/fonts project). GitHub Pages serves them with
+Access-Control-Allow-Origin: *, so the same glyphs URL also works when the style itself is served
+from golftiles.org. Longer term the plan is: golftiles.org is the bucket endpoint for tiles and
+style, and the GitHub Pages site is the demo page.
+
+
+
+
+Geometry/attribute placement decisions the style relies on (all from custom-tilemaker/process.lua):
+- waterway=* ways are written to the golf_lines layer (not golf_areas). The "Streams and Rivers"
+ style layer therefore reads source-layer golf_lines.
+- natural=water polygons are written to golf_areas with the attribute water=lake or water=river.
+ The "Lakes and rivers" style layer renders both values.
+- area:highway=* polygons are written with the attribute key area_highway (colon replaced with an
+ underscore, since expressions like ["get", "area:highway"] would read awkwardly and the colon has
+ no meaning in the tiles). The "Area:highway" style layer filters on area_highway.
+- Hole labels read hole_number (the renamed ref, see above), not ref.