UNPKG

agentscript

Version:

AgentScript Model in Model/View architecture

172 lines (140 loc) 5.94 kB
import * as util from '../src/utils.js' import * as gis from '../src/gis.js' import * as TileData from '../src/TileData.js' import * as L from 'https://unpkg.com/leaflet@1.8.0/dist/leaflet-src.esm.js' import elementOverlay from '../vendor/elementOverlay.js' function defaultLeafletOptions() { return { // L.map uses these div: 'map', Z: 10, // have javascript install css files fetchCSS: true, // the L.map options // preferCanvas seems to be needed for model on top of json? mapOptions: { zoomDelta: 0.25, zoomSnap: 0, preferCanvas: true }, // no elevation layer. 0.01 for invisible elevation layer, 1 for opaque elevationOpacity: 0, // model's border: set to null for no border. can also be used for fill color bboxBorder: { color: 'red', weight: 2 }, // tiles's border: set to null for no border, uses css format for now. tilesBorder: 'solid red 2px', // map base layer: osm topo topo1 smooth usgs terrain: 'topo', // elevation tiles: redfishUSA/World, mapzen, mapbox tiles: 'mapzen', // Add Leaflet gis layer using the provided style // https://leafletjs.com/reference.html#geojson // https://leafletjs.com/reference.html#layer json: null, // jsonStyle must be a function: geoJsonFeature => ({color:...}) // default style is leaflet's: // https://leafletjs.com/reference.html#path-option jsonStyle: feature => ({ // put styles here. none => use leaflet defaults color: 'red', }), jsonPopup: null, // ToDo: // A popup, bound to a layer. Must be a function: layer => string // Ex: ['jsonLayer', layer => layer.feature.properties.NAME] // see: https://leafletjs.com/reference.html#popup // popup: [], } } async function leafletInit(model, canvas, options = {}) { if (!model.world.bbox) throw Error('leafletInit: model must use GeoWorld') // ========== Startup: css, tile datasets, terrain layer ========== options = Object.assign(defaultLeafletOptions(), options) // If options.fetchCSS use JS to set Leaflet & our css files if (options.fetchCSS) { await util.fetchCssStyle('https://unpkg.com/leaflet/dist/leaflet.css') await util.fetchCssStyle('./map.css') // await util.fetchCssStyle('https://code.agentscript.org/gis/map.css') } // Get one of the 4 tile datasets const tileData = TileData[options.tiles] // redfishUSA/World, mapzen, mapbox // Name of the terrain layer (from the gis.js module) const terrainName = options.terrain // ========== Start of map layers: ========== // ===== The map using the div, model center and Z. World is a GeoWorld const center = gis.latlon(model.world.bboxCenter()) const map = L.map(options.div, options.mapOptions) map.setView(center, options.Z) // ===== Map's terrain const terrainLayer = L.tileLayer(gis.template(terrainName), { attribution: gis.attribution(terrainName), // className: 'terrain-pane', // shows tiles borders }).addTo(map) // ===== elevation layer if non-zero elevationOpacity let elevationLayer if (options.elevationOpacity > 0) { elevationLayer = L.tileLayer(tileData.zxyTemplate, { opacity: options.elevationOpacity, attribution: 'Elevation Tiles', crossOrigin: '', maxZoom: tileData.maxZoom, // larger mapzen zoom yields tileerror }).addTo(map) } // ===== A border around the model // Draw a border around the model's bbox // Before done via css: this.canvas.style.border = options.canvasBorder // where canvasBorder: '2px solid red' // .. but prefer a map layer for keeping it all in Leaflet let bboxLayer if (options.bboxBorder) { const latlngs = gis.latlon(gis.bboxCoords(model.world.bbox)) // bboxLayer = L.polyline(latlngs, options.bboxBorder).addTo(map) bboxLayer = L.rectangle(latlngs, options.bboxBorder).addTo(map) } // ===== Draw a border around each tile, using css, not Leaflet // https://gis.stackexchange.com/questions/149062/display-tile-grid-borders-with-leaflet-visual-debugging if (options.tilesBorder !== 'solid red 2px') { if (!options.tilesBorder) options.tilesBorder = '0px' const root = document.documentElement root.style.setProperty('--tile-border', options.tilesBorder) } // ===== A JSON layer with optional popup, fairly common let jsonLayer if (options.json) { jsonLayer = L.geoJSON(options.json, { style: options.jsonStyle, }) if (options.jsonPopup) { jsonLayer.bindPopup(options.jsonPopup) } jsonLayer.addTo(map) } // ===== The model layer, using Cody's ElementOverlay // Should be last layer, on top const [west, south, east, north] = model.world.bbox const bounds = new L.LatLngBounds( new L.LatLng(north, west), new L.LatLng(south, east) ) const ElementOverlay = elementOverlay(L) const elementLayer = new ElementOverlay(canvas, bounds).addTo(map) // ========== End of map layers ========== return { // a module of all the elevation tile urls & their datasets TileData, tileData, // our instance of TileData gis, // the gis utilities module // The leaflet map, and input for L.map L, map, terrainName, // The leaflet layerrs terrainLayer, elevationLayer, elementLayer, jsonLayer, bboxLayer, // The model's overlay layer elementOverlay, ElementOverlay, // the input options, possibly modified above options, } } export default leafletInit