removing non-openlayers code, setting map up on index page

This commit is contained in:
Nat Hillard 2021-05-05 23:17:08 -04:00
parent e7d02e9b1a
commit 81e7027a4e
12 changed files with 10520 additions and 6979 deletions

View file

@ -6,13 +6,7 @@ module.exports = {
description: `Front end for Justice40 mappping tool project`,
navigation: [
{
items: [{ text: 'Mapbox', link: '/mapbox' }],
},
{
items: [{ text: 'Leaflet', link: '/leaflet' }],
},
{
items: [{ text: 'OpenLayers', link: '/openlayers' }],
items: [{ text: 'Map', link: '/index' }],
},
],
secondaryLinks: [
@ -80,7 +74,6 @@ module.exports = {
name: `markdown-pages`,
},
},
`gatsby-transformer-remark`,
`gatsby-plugin-react-leaflet`
`gatsby-transformer-remark`
],
};

File diff suppressed because it is too large Load diff

View file

@ -15,30 +15,22 @@
"clean": "gatsby clean"
},
"dependencies": {
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"clipboardy": "^2.3.0",
"colormap": "^2.3.2",
"d3": "^6.7.0",
"gatsby": "^3.2.1",
"gatsby-plugin-image": "^1.3.0",
"gatsby-plugin-manifest": "^3.3.0",
"gatsby-plugin-mdx": "^2.3.0",
"gatsby-plugin-react-helmet": "^4.3.0",
"gatsby-plugin-react-leaflet": "^3.0.0",
"gatsby-plugin-sass": "^4.3.0",
"gatsby-plugin-sharp": "^3.3.0",
"gatsby-plugin-sitemap": "^3.3.0",
"gatsby-source-filesystem": "^3.3.0",
"gatsby-transformer-remark": "^4.0.0",
"gatsby-transformer-sharp": "^3.3.0",
"leaflet": "^1.7.1",
"mapbox-gl": "^2.2.0",
"gatsby": "^3.4.1",
"gatsby-cli": "^3.4.1",
"gatsby-plugin-image": "^1.4.0",
"gatsby-plugin-manifest": "^3.4.0",
"gatsby-plugin-mdx": "^2.4.0",
"gatsby-plugin-react-helmet": "^4.4.0",
"gatsby-plugin-sass": "^4.4.0",
"gatsby-plugin-sitemap": "^4.0.0",
"gatsby-transformer-remark": "^4.1.0",
"gatsby-transformer-sharp": "^3.4.0",
"ol": "^6.5.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-leaflet": "^3.1.0",
"react-map-gl": "^6.1.12",
"sass": "^1.32.8",
"uswds": "^2.11.1"
}

View file

@ -2,97 +2,100 @@
import React, { useState, useEffect, useRef } from 'react';
// openlayers
import Map from 'ol/Map'
import View from 'ol/View'
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import XYZ from 'ol/source/XYZ'
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import MVT from 'ol/format/MVT.js';
import VectorTileLayer from 'ol/layer/VectorTile.js';
import VectorTileSource from 'ol/source/VectorTile.js';
import {Fill, Style} from 'ol/style.js';
import {fromLonLat} from 'ol/proj';
import colormap from 'colormap';
function OlMapWrapper(props) {
import * as styles from "./ol-map-wrapper.module.css";
const min = 0;
const max = 1;
const steps = 10;
const ramp = colormap({
colormap: 'freesurface-blue',
nshades: steps
});
function clamp(value, low, high) {
return Math.max(low, Math.min(value, high));
}
function getColor(data) {
const f = Math.pow(clamp((data - min) / (max - min), 0, 1), 1 / 2);
const index = Math.round(f * (steps - 1));
return ramp[index];
}
function OlMapWrapper() {
// set intial state
const [ map, setMap ] = useState()
const [ featuresLayer, setFeaturesLayer ] = useState()
// pull refs
const mapElement = useRef()
// create state ref that can be accessed in OpenLayers onclick callback function
// https://stackoverflow.com/a/60643670
const mapRef = useRef()
mapRef.current = map
// initialize map on first render - logic formerly put into componentDidMount
useEffect( () => {
const xyzSource = new VectorTileSource({
format: new MVT(),
url: 'http://localhost:7800/public.maryland/{z}/{x}/{y}.mvt'
});
// create and add vector source layer
const initalFeaturesLayer = new VectorLayer({
source: new VectorSource()
})
// create map
var vtLayer = new VectorTileLayer({
declutter: false,
source: xyzSource,
style: function(feature) {
const data = feature.get('lowincpct');
return new Style({
fill: new Fill({
color: getColor(data)
}),
});
}
});
const initialMap = new Map({
target: mapElement.current,
layers: [
// USGS Topo
new TileLayer({
source: new XYZ({
url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}',
url: 'http://{a-d}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
})
}),
// Google Maps Terrain
/* new TileLayer({
source: new XYZ({
url: 'http://mt0.google.com/vt/lyrs=p&hl=en&x={x}&y={y}&z={z}',
})
}), */
initalFeaturesLayer
vtLayer
],
view: new View({
projection: 'EPSG:3857',
center: [39.0458, -76.6413],
zoom: 9
center: fromLonLat([-76.6413, 39.0458]),
zoom: 7,
}),
controls: []
})
// save map and vector layer references to state
setMap(initialMap)
setFeaturesLayer(initalFeaturesLayer)
initialMap.once('rendercomplete', ()=>{
performance.mark("MAP_IDLE");
console.log("OL IS IDLE");
});
vtLayer.once('tileloadend', function () {
performance.mark("STYLE_LOADED");
console.log("STYLE LOADED");
});
},[])
// update map if features prop changes - logic formerly put into componentDidUpdate
useEffect( () => {
if (props.features.length) { // may be null on first render
// set features to map
featuresLayer.setSource(
new VectorSource({
features: props.features // make sure features is an array
})
)
// fit map to feature extent (with 100px of padding)
map.getView().fit(featuresLayer.getSource().getExtent(), {
padding: [100,100,100,100]
})
}
},[props.features])
// render component
return (
<div className="map-wrapper">
<div ref={mapElement} id="ol-map" className="map-container"></div>
</div>
<div ref={mapElement} className={styles.map}></div>
)
}
export default OlMapWrapper

View file

@ -0,0 +1,3 @@
.map {
height: 500px;
}

View file

@ -1,13 +1,20 @@
import React from 'react';
import Layout from '../components/layout';
import SEO from '../components/seo';
import OlMapWrapper from '../components/ol-map-wrapper';
import * as styles from "./index.module.css";
const IndexPage = () => {
return (
<Layout>
<SEO title="Justice 40 Home" />
<div>
Map goes here
<div className={`grid-container .height-auto`}>
<div className="grid-row .height-auto">
<div className="grid-col-8">
<OlMapWrapper />
</div>
<div className="grid-col-4"></div>
</div>
</div>
</Layout>
)

View file

@ -0,0 +1,3 @@
.gridContainer {
height: 500px;
}

View file

@ -1,45 +0,0 @@
import * as React from "react";
import { MapContainer, TileLayer, Marker, Popup, GeoJSON, FeatureGroup } from 'react-leaflet'
import geojson from "../data/maryland.json";
import Layout from '../components/layout';
const LeafletMap = () => {
return (
<MapContainer
center={[39.0458, -76.6413]}
zoom={8}
style={{ height: "50vh" }}
>
<TileLayer
attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}@2x.png"
/>
<FeatureGroup
pathOptions={{ weight:0.1,
color: 'black',
fillColor: 'grey',
"fill-opacity": 0.5 }}
>
<GeoJSON data={geojson}></GeoJSON>
</FeatureGroup>
<Marker position={[51.505, -0.09]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
);
};
const LeafletPage = () => {
return (
<Layout>
<LeafletMap />
</Layout>
);
};
export default LeafletPage

View file

@ -1,119 +0,0 @@
import React, { useRef, useEffect, useCallback, useState } from 'react';
import Layout from '../components/layout';
import ReactMapGL, {Layer, Source} from 'react-map-gl';
import * as mapboxStyles from "./mapbox.module.css";
const xyzSource = {
name: "public.maryland",
scheme: 'xyz',
tilejson: "2.0.0",
minzoom: 0,
maxzoom: 22,
prefetchable: true,
tiles: ["http://localhost:7800/public.maryland/{z}/{x}/{y}.mvt"],
type: 'vector'
};
const layerStyle = {
id: 'public.maryland.MultiPolygon.fill',
type: 'fill',
source: "public.maryland",
"source-layer": "public.maryland",
paint: {
"fill-color": [
"interpolate",
["linear"],
["get", "lowincpct"],
0,
"white",
1,
"rgb(0,94,162)"
],
"fill-opacity": 0.5
}
};
const mapStyle = {
'version': 8,
'cursor': 'pointer',
'sources': {
'carto-light': {
'type': 'raster',
'tiles': [
"https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}@2x.png",
"https://b.basemaps.cartocdn.com/light_all/{z}/{x}/{y}@2x.png",
"https://c.basemaps.cartocdn.com/light_all/{z}/{x}/{y}@2x.png",
"https://d.basemaps.cartocdn.com/light_all/{z}/{x}/{y}@2x.png"
]
}
},
'layers': [{
'id': 'carto-light-layer',
'source': 'carto-light',
'type': 'raster',
'minzoom': 0,
'maxzoom': 22
}]
};
const MapboxMap = () => {
const [viewport, setViewport] = useState({
latitude: 39.289444,
longitude: -76.615278,
zoom: 8
});
const [hoverInfo, setHoverInfo] = useState(null);
const onHover = useCallback(event => {
const {
features,
srcEvent: {offsetX, offsetY}
} = event;
const hoveredFeature = features && features[0];
setHoverInfo(
hoveredFeature
? {
feature: hoveredFeature,
x: offsetX,
y: offsetY
}
: null
);
}, []);
return (
<ReactMapGL
{...viewport}
mapboxApiAccessToken={process.env.GATSBY_MAPBOX_ACCESS_TOKEN}
width="100%"
height="100%"
onViewportChange={(viewport) => setViewport(viewport)}
mapStyle={mapStyle}
onHover={onHover}
>
<Source type="vector" {...xyzSource}>
<Layer {...layerStyle} />
</Source>
{hoverInfo && (
<div className={mapboxStyles.tooltip} style={{left: hoverInfo.x, top: hoverInfo.y}}>
<div>ID: {hoverInfo.feature.properties.id}</div>
<div>Percent Low Income: {parseFloat(hoverInfo.feature.properties.lowincpct * 100).toFixed(2)+"%"}</div>
</div>
)}
</ReactMapGL>
);
}
const MapboxPage = () => {
return (
<Layout>
<div className={mapboxStyles.mapContainer}>
<MapboxMap />
</div>
</Layout>
);
};
export default MapboxPage

View file

@ -1,19 +0,0 @@
.mapContainer {
height: 50vh;
width: 100%;
display: flex;
flex-direction: column;
align-content: center;
}
.tooltip {
position: absolute;
margin: 8px;
padding: 4px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
max-width: 300px;
font-size: 10px;
z-index: 9;
pointer-events: none;
}

View file

@ -1,39 +0,0 @@
import React, { useState, useEffect } from 'react';
import Layout from '../components/layout';
import SEO from '../components/seo';
import GeoJSON from 'ol/format/GeoJSON'
import OlMapWrapper from '../components/ol-map-wrapper'
import geojson from "../data/maryland.json";
const OpenLayersPage = () => {
// set intial state
const [ features, setFeatures ] = useState([])
// initialization - retrieve GeoJSON features
useEffect( () => {
// parse fetched geojson into OpenLayers features
// use options to convert feature from EPSG:4326 to EPSG:3857
const wktOptions = {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
}
const parsedFeatures = new GeoJSON().readFeatures(geojson, wktOptions)
setFeatures(parsedFeatures)
},[])
return (
<>
<Layout>
<SEO title="OpenLayers" />
<h1 className="margin-left-9">OpenLayers</h1>
<OlMapWrapper features={features} />
</Layout>
</>
)
}
export default OpenLayersPage

View file

@ -7,15 +7,3 @@ $theme-font-path: "../../node_modules/uswds/src/fonts";
@import "../../node_modules/uswds/";
@import "../../node_modules/ol/ol.css";
@import "../../node_modules/mapbox-gl/src/css/mapbox-gl.css";
#map {
height: 180px;
}
#ol-map {
min-width: 600px;
min-height: 50vh;
height: 500px;
width: 100%;
}