Skip to content

Commit

Permalink
Generate stylesheets internally (re: #94)
Browse files Browse the repository at this point in the history
  • Loading branch information
quincylvania committed Dec 13, 2024
1 parent 73a3ff9 commit bb0e7d8
Show file tree
Hide file tree
Showing 96 changed files with 2,425 additions and 1,751 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ We also collaborate via the [#opentrailmap](https://osmus.slack.com/archives/ope
5. Visit [http://localhost:4001](http://localhost:4001) in your browser
6. That's it!

#### Building sprites

Source vector images for use in the map are located at [/style/sprites/svg/](/style/sprites/svg/). If you add or change any of these, you'll need to rebuild the spritesheets.

1. Install the [spreet](https://github.com/flother/spreet) command line tool
2. Run `npm run sprites`

## License

The OpenTrailMap source code is distributed under the [MIT license](https://github.com/osmus/OpenTrailMap/blob/main/LICENSE). Dependencies are subject to their respective licenses.
Binary file removed img/map/beaver_dam-canoeable.png
Binary file not shown.
Binary file removed img/map/beaver_dam-hazard.png
Binary file not shown.
Binary file removed img/map/beaver_dam.png
Binary file not shown.
Binary file removed img/map/bothways-arrows.png
Binary file not shown.
Binary file removed img/map/cairn.png
Binary file not shown.
Binary file removed img/map/campground-noaccess.png
Binary file not shown.
Binary file removed img/map/campground.png
Binary file not shown.
Binary file removed img/map/campsite.png
Binary file not shown.
Binary file removed img/map/canoe-noaccess.png
Binary file not shown.
Binary file removed img/map/canoe.png
Binary file not shown.
Binary file removed img/map/caravan_site-noaccess.png
Binary file not shown.
Binary file removed img/map/caravan_site.png
Binary file not shown.
Binary file removed img/map/dam-canoeable.png
Binary file not shown.
Binary file removed img/map/dam-hazard.png
Binary file not shown.
Binary file removed img/map/dam.png
Binary file not shown.
Binary file removed img/map/disallowed-stripes.png
Binary file not shown.
Binary file removed img/map/ferry.png
Binary file not shown.
Binary file removed img/map/guidepost.png
Binary file not shown.
Binary file removed img/map/lean_to.png
Binary file not shown.
Binary file removed img/map/lock-canoeable.png
Binary file not shown.
Binary file removed img/map/lock-hazard.png
Binary file not shown.
Binary file removed img/map/lock.png
Binary file not shown.
Binary file removed img/map/nature_reserve.png
Binary file not shown.
Binary file removed img/map/oneway-arrow-left.png
Binary file not shown.
Binary file removed img/map/oneway-arrow-right.png
Binary file not shown.
Binary file removed img/map/park.png
Diff not rendered.
Binary file removed img/map/peak.png
Diff not rendered.
Binary file removed img/map/protected_area.png
Diff not rendered.
Binary file removed img/map/question.png
Diff not rendered.
Binary file removed img/map/ranger_station.png
Diff not rendered.
Binary file removed img/map/restricted-zone.png
Diff not rendered.
Binary file removed img/map/route_marker.png
Diff not rendered.
Binary file removed img/map/slipway-canoe-noaccess.png
Diff not rendered.
Binary file removed img/map/slipway-canoe-trailer-noaccess.png
Diff not rendered.
Binary file removed img/map/slipway-canoe-trailer.png
Diff not rendered.
Binary file removed img/map/slipway-canoe.png
Diff not rendered.
Binary file removed img/map/streamgage.png
Diff not rendered.
Binary file removed img/map/trailhead.png
Diff not rendered.
Binary file removed img/map/viewpoint.png
Diff not rendered.
Binary file removed img/map/waterfall-canoeable.png
Diff not rendered.
Binary file removed img/map/waterfall-hazard.png
Diff not rendered.
Binary file removed img/map/waterfall.png
Diff not rendered.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ <h1 style="display:flex;"><span style="flex-basis: 100%;"><span class="swatch"><
</div>
<script type="application/javascript" src="dist/turf-buffer.js"></script>
<script type="application/javascript" src="js/utils.js"></script>
<script type="application/javascript" src="js/styleGenerator.js"></script>
<script type="application/javascript" src="js/mapController.js"></script>
<script type="application/javascript" src="js/sidebarController.js"></script>
<script type="application/javascript" src="js/dataController.js"></script>
Expand Down
10 changes: 5 additions & 5 deletions js/hashController.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ function selectedEntityInfoFromHash() {
return null;
}

function updateForHash() {
setTravelMode(hashValue("mode"));
setLens(hashValue("lens"));
selectEntity(selectedEntityInfoFromHash());
focusEntity(focusedEntityInfoFromHash());
function updateForHash(skipMapUpdate) {
setTravelMode(hashValue("mode"), skipMapUpdate);
setLens(hashValue("lens"), skipMapUpdate);
selectEntity(selectedEntityInfoFromHash(), skipMapUpdate);
focusEntity(focusedEntityInfoFromHash(), skipMapUpdate);
hashValue("inspect") ? openSidebar() : closeSidebar();
}
205 changes: 22 additions & 183 deletions js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,117 +255,7 @@ function isValidEntityInfo(entityInfo) {
entityInfo?.id > 0;
}

function compositeGeoJson(features) {
if (!features.length) return;
let coordinates = [];
features.forEach(function(feature) {
if (feature.geometry.type === 'Polygon') {
coordinates.push(feature.geometry.coordinates);
} else if (feature.geometry.type === 'MultiPolygon') {
coordinates = coordinates.concat(feature.geometry.coordinates);
}
});
return {
type: "Feature",
geometry: {
type: "MultiPolygon",
coordinates: coordinates,
},
properties: features[0].properties
};
}

let focusAreaGeoJson;
let focusAreaGeoJsonBuffered;
let focusAreaBoundingBox;

function getEntityBoundingBox(entity) {
const props = entity?.properties;
if (props?.hasOwnProperty('MIN_LON') &&
props?.hasOwnProperty('MIN_LAT') &&
props?.hasOwnProperty('MAX_LON') &&
props?.hasOwnProperty('MAX_LAT')) {
return [
props.MIN_LON,
props.MIN_LAT,
props.MAX_LON,
props.MAX_LAT
];
}
}

function getEntityBoundingBoxFromLayer(id, type, layer) {
if (!focusedEntityInfo) return null;
let features = map.querySourceFeatures('trails', {
filter: [
"all",
["==", ["get", "OSM_ID"], id],
["==", ["get", "OSM_TYPE"], type],
],
sourceLayer: layer,
});
if (features.length) {
return getEntityBoundingBox(features[0]);
}
}

function buildFocusAreaGeoJson() {
if (!focusedEntityInfo) return null;
let results = map.querySourceFeatures('trails', {
filter: [
"all",
["==", ["get", "OSM_ID"], focusedEntityInfo.id],
["==", ["get", "OSM_TYPE"], focusedEntityInfo.type],
],
sourceLayer: "park",
});
return compositeGeoJson(results);
}
// check the current extent of the map, and if focused area is too far offscreen, put it back onscreen
function checkMapExtent() {
if (!focusAreaBoundingBox) return;
let currentBounds = map.getBounds();
let targetBounds = currentBounds.toArray();
let width = focusAreaBoundingBox[2] - focusAreaBoundingBox[0];
let height = focusAreaBoundingBox[3] - focusAreaBoundingBox[1];
let maxExtent = Math.max(width, height);
let margin = maxExtent / 4;

if (currentBounds.getNorth() < focusAreaBoundingBox[1] - margin) targetBounds[1][1] = focusAreaBoundingBox[1] + margin;
if (currentBounds.getSouth() > focusAreaBoundingBox[3] + margin) targetBounds[0][1] = focusAreaBoundingBox[3] - margin;
if (currentBounds.getEast() < focusAreaBoundingBox[0] - margin) targetBounds[1][0] = focusAreaBoundingBox[0] + margin;
if (currentBounds.getWest() > focusAreaBoundingBox[2] + margin) targetBounds[0][0] = focusAreaBoundingBox[2] - margin;
if (currentBounds.toArray().toString() !== targetBounds.toString()) {
map.fitBounds(targetBounds);
}
}

function fitMapToBounds(bbox) {
let width = bbox[2] - bbox[0];
let height = bbox[3] - bbox[1];
let maxExtent = Math.max(width, height);
let fitBbox = extendBbox(bbox, maxExtent / 16);
map.fitBounds(fitBbox);
}

function reloadFocusAreaIfNeeded() {
let newFocusAreaGeoJson = buildFocusAreaGeoJson();

if ((newFocusAreaGeoJson && JSON.stringify(newFocusAreaGeoJson)) !==
(focusAreaGeoJson && JSON.stringify(focusAreaGeoJson))) {

focusAreaBoundingBox = focusedEntityInfo && getEntityBoundingBoxFromLayer(focusedEntityInfo.id, focusedEntityInfo.type, "park");

focusAreaGeoJson = newFocusAreaGeoJson;
focusAreaGeoJsonBuffered = focusAreaGeoJson?.geometry?.coordinates?.length ? turfBuffer.buffer(focusAreaGeoJson, 0.25, {units: 'kilometers'}) : focusAreaGeoJson;

if (focusAreaGeoJson) document.getElementById("map-title").innerText = focusAreaGeoJson.properties.name;

updateTrailLayers();
}
}

function focusEntity(entityInfo) {
function focusEntity(entityInfo, skipMapUpdate) {
if (!isValidEntityInfo(entityInfo)) entityInfo = null;

if (focusedEntityInfo?.id === entityInfo?.id &&
Expand All @@ -388,11 +278,13 @@ function focusEntity(entityInfo) {
document.getElementById("map-title").innerText = '';
document.getElementById("nameplate").style.display = focusedEntityInfo ? 'flex' : 'none';

reloadFocusAreaIfNeeded();
updateMapForSelection();
if (!skipMapUpdate) {
reloadFocusAreaIfNeeded();
updateMapForSelection();
}
}

function selectEntity(entityInfo) {
function selectEntity(entityInfo, skipMapUpdate) {

if (selectedEntityInfo?.id === entityInfo?.id &&
selectedEntityInfo?.type === entityInfo?.type
Expand All @@ -407,8 +299,10 @@ function selectEntity(entityInfo) {
selected: selectedEntityInfo ? type + "/" + entityId : null
});

updateMapForSelection();
updateMapForHover();
if (!skipMapUpdate) {
updateMapForSelection();
updateMapForHover();
}

if (isSidebarOpen()) updateSidebar(selectedEntityInfo);

Expand All @@ -421,6 +315,7 @@ function selectEntity(entityInfo) {
});
}
}

function updateLensControl() {
let html = "";
let items = lensOptionsByMode[travelMode];
Expand All @@ -440,7 +335,7 @@ function updateLensControl() {
lensElement.innerHTML = html;
lensElement.value = lens;
}
function setTravelMode(value) {
function setTravelMode(value, skipMapUpdate) {
if (value === null) value = defaultTravelMode;
if (travelMode === value) return;
travelMode = value;
Expand All @@ -450,7 +345,7 @@ function setTravelMode(value) {
document.getElementById("travel-mode").value = travelMode;

updateLensControl();
updateTrailLayers();
if (!skipMapUpdate) reloadMapStyle();
setHashParameters({ mode: travelMode === defaultTravelMode ? null : value });
}
function setLens(value, skipMapUpdate) {
Expand All @@ -462,13 +357,15 @@ function setLens(value, skipMapUpdate) {

document.getElementById("lens").value = lens;

if (!skipMapUpdate) updateTrailLayers();
if (!skipMapUpdate) reloadMapStyle();
setHashParameters({ lens: lens === defaultLens ? null : value });
}

window.onload = function(event) {
window.onload = function() {

window.addEventListener("hashchange", updateForHash);
window.addEventListener("hashchange", function() {
updateForHash(false);
});

document.addEventListener('keydown', function(e) {

Expand Down Expand Up @@ -518,9 +415,10 @@ window.onload = function(event) {
map = new maplibregl.Map({
container: 'map',
hash: "map",
style: './styles/basemap.json',
style: './style/basestyle.json',
center: initialCenter,
zoom: initialZoom
zoom: initialZoom,
fadeDuration: 0,
});

// Add zoom and rotation controls to the map.
Expand All @@ -539,65 +437,6 @@ window.onload = function(event) {
unit: 'imperial'
}), "bottom-left");

const imageToLoad = [
'beaver_dam',
'beaver_dam-canoeable',
'beaver_dam-hazard',
'bothways-arrows',
'cairn',
'campground',
'campground-noaccess',
'campsite',
'canoe',
'canoe-noaccess',
'caravan_site',
'caravan_site-noaccess',
'dam',
'dam-canoeable',
'dam-hazard',
'disallowed-stripes',
'ferry',
'guidepost',
'lean_to',
'lock',
'lock-canoeable',
'lock-hazard',
'nature_reserve',
'oneway-arrow-right',
'oneway-arrow-left',
'question',
'park',
'peak',
'protected_area',
'ranger_station',
'restricted-zone',
'route_marker',
'slipway-canoe-trailer',
'slipway-canoe-trailer-noaccess',
'slipway-canoe',
'slipway-canoe-noaccess',
'streamgage',
'trailhead',
'viewpoint',
'waterfall',
'waterfall-canoeable',
'waterfall-hazard',
];

for (let i in imageToLoad) {
let img = imageToLoad[i];
map.loadImage('img/map/' + img + '.png').then(function(resp) {
return map.addImage(img, resp.data, { pixelRatio: 2 });
});
}

map
.on('load', loadInitialMap)
.on('moveend', function(event) {
if (localStorage) {
let transform = map.getCenter();
transform.zoom = map.getZoom();
localStorage.setItem('map_transform', JSON.stringify(transform));
}
});
.on('load', loadInitialMap);
}
Loading

0 comments on commit bb0e7d8

Please sign in to comment.