mirror of
https://github.com/DOI-DO/j40-cejst-2.git
synced 2025-02-23 10:04:18 -08:00
removing non-openlayers code, setting map up on index page
This commit is contained in:
parent
e7d02e9b1a
commit
81e7027a4e
12 changed files with 10520 additions and 6979 deletions
|
@ -6,13 +6,7 @@ module.exports = {
|
||||||
description: `Front end for Justice40 mappping tool project`,
|
description: `Front end for Justice40 mappping tool project`,
|
||||||
navigation: [
|
navigation: [
|
||||||
{
|
{
|
||||||
items: [{ text: 'Mapbox', link: '/mapbox' }],
|
items: [{ text: 'Map', link: '/index' }],
|
||||||
},
|
|
||||||
{
|
|
||||||
items: [{ text: 'Leaflet', link: '/leaflet' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
items: [{ text: 'OpenLayers', link: '/openlayers' }],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
secondaryLinks: [
|
secondaryLinks: [
|
||||||
|
@ -80,7 +74,6 @@ module.exports = {
|
||||||
name: `markdown-pages`,
|
name: `markdown-pages`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
`gatsby-transformer-remark`,
|
`gatsby-transformer-remark`
|
||||||
`gatsby-plugin-react-leaflet`
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
17056
justice40-frontend/package-lock.json
generated
17056
justice40-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -15,30 +15,22 @@
|
||||||
"clean": "gatsby clean"
|
"clean": "gatsby clean"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mdx-js/mdx": "^1.6.22",
|
"colormap": "^2.3.2",
|
||||||
"@mdx-js/react": "^1.6.22",
|
|
||||||
"clipboardy": "^2.3.0",
|
|
||||||
"d3": "^6.7.0",
|
"d3": "^6.7.0",
|
||||||
"gatsby": "^3.2.1",
|
"gatsby": "^3.4.1",
|
||||||
"gatsby-plugin-image": "^1.3.0",
|
"gatsby-cli": "^3.4.1",
|
||||||
"gatsby-plugin-manifest": "^3.3.0",
|
"gatsby-plugin-image": "^1.4.0",
|
||||||
"gatsby-plugin-mdx": "^2.3.0",
|
"gatsby-plugin-manifest": "^3.4.0",
|
||||||
"gatsby-plugin-react-helmet": "^4.3.0",
|
"gatsby-plugin-mdx": "^2.4.0",
|
||||||
"gatsby-plugin-react-leaflet": "^3.0.0",
|
"gatsby-plugin-react-helmet": "^4.4.0",
|
||||||
"gatsby-plugin-sass": "^4.3.0",
|
"gatsby-plugin-sass": "^4.4.0",
|
||||||
"gatsby-plugin-sharp": "^3.3.0",
|
"gatsby-plugin-sitemap": "^4.0.0",
|
||||||
"gatsby-plugin-sitemap": "^3.3.0",
|
"gatsby-transformer-remark": "^4.1.0",
|
||||||
"gatsby-source-filesystem": "^3.3.0",
|
"gatsby-transformer-sharp": "^3.4.0",
|
||||||
"gatsby-transformer-remark": "^4.0.0",
|
|
||||||
"gatsby-transformer-sharp": "^3.3.0",
|
|
||||||
"leaflet": "^1.7.1",
|
|
||||||
"mapbox-gl": "^2.2.0",
|
|
||||||
"ol": "^6.5.0",
|
"ol": "^6.5.0",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-leaflet": "^3.1.0",
|
|
||||||
"react-map-gl": "^6.1.12",
|
|
||||||
"sass": "^1.32.8",
|
"sass": "^1.32.8",
|
||||||
"uswds": "^2.11.1"
|
"uswds": "^2.11.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,97 +2,100 @@
|
||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
// openlayers
|
// openlayers
|
||||||
import Map from 'ol/Map'
|
import Map from 'ol/Map';
|
||||||
import View from 'ol/View'
|
import View from 'ol/View';
|
||||||
import TileLayer from 'ol/layer/Tile'
|
import TileLayer from 'ol/layer/Tile';
|
||||||
import VectorLayer from 'ol/layer/Vector'
|
import XYZ from 'ol/source/XYZ';
|
||||||
import VectorSource from 'ol/source/Vector'
|
import MVT from 'ol/format/MVT.js';
|
||||||
import XYZ from 'ol/source/XYZ'
|
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
|
// set intial state
|
||||||
const [ map, setMap ] = useState()
|
const [ map, setMap ] = useState()
|
||||||
const [ featuresLayer, setFeaturesLayer ] = useState()
|
|
||||||
|
|
||||||
// pull refs
|
// pull refs
|
||||||
const mapElement = useRef()
|
const mapElement = useRef()
|
||||||
|
|
||||||
// create state ref that can be accessed in OpenLayers onclick callback function
|
|
||||||
// https://stackoverflow.com/a/60643670
|
|
||||||
const mapRef = useRef()
|
const mapRef = useRef()
|
||||||
mapRef.current = map
|
mapRef.current = map
|
||||||
|
|
||||||
// initialize map on first render - logic formerly put into componentDidMount
|
// initialize map on first render - logic formerly put into componentDidMount
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
|
const xyzSource = new VectorTileSource({
|
||||||
|
format: new MVT(),
|
||||||
|
url: 'http://localhost:7800/public.maryland/{z}/{x}/{y}.mvt'
|
||||||
|
});
|
||||||
|
|
||||||
// create and add vector source layer
|
var vtLayer = new VectorTileLayer({
|
||||||
const initalFeaturesLayer = new VectorLayer({
|
declutter: false,
|
||||||
source: new VectorSource()
|
source: xyzSource,
|
||||||
})
|
style: function(feature) {
|
||||||
|
const data = feature.get('lowincpct');
|
||||||
// create map
|
return new Style({
|
||||||
|
fill: new Fill({
|
||||||
|
color: getColor(data)
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
const initialMap = new Map({
|
const initialMap = new Map({
|
||||||
target: mapElement.current,
|
target: mapElement.current,
|
||||||
layers: [
|
layers: [
|
||||||
|
|
||||||
// USGS Topo
|
|
||||||
new TileLayer({
|
new TileLayer({
|
||||||
source: new XYZ({
|
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',
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
vtLayer
|
||||||
// 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
|
|
||||||
|
|
||||||
],
|
],
|
||||||
view: new View({
|
view: new View({
|
||||||
projection: 'EPSG:3857',
|
center: fromLonLat([-76.6413, 39.0458]),
|
||||||
center: [39.0458, -76.6413],
|
zoom: 7,
|
||||||
zoom: 9
|
|
||||||
}),
|
}),
|
||||||
controls: []
|
controls: []
|
||||||
})
|
})
|
||||||
|
|
||||||
// save map and vector layer references to state
|
|
||||||
setMap(initialMap)
|
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");
|
||||||
|
});
|
||||||
|
|
||||||
},[])
|
},[])
|
||||||
|
// render component
|
||||||
// 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])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="map-wrapper">
|
<div ref={mapElement} className={styles.map}></div>
|
||||||
<div ref={mapElement} id="ol-map" className="map-container"></div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default OlMapWrapper
|
export default OlMapWrapper
|
|
@ -0,0 +1,3 @@
|
||||||
|
.map {
|
||||||
|
height: 500px;
|
||||||
|
}
|
|
@ -1,13 +1,20 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Layout from '../components/layout';
|
import Layout from '../components/layout';
|
||||||
import SEO from '../components/seo';
|
import SEO from '../components/seo';
|
||||||
|
import OlMapWrapper from '../components/ol-map-wrapper';
|
||||||
|
import * as styles from "./index.module.css";
|
||||||
|
|
||||||
const IndexPage = () => {
|
const IndexPage = () => {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<SEO title="Justice 40 Home" />
|
<SEO title="Justice 40 Home" />
|
||||||
<div>
|
<div className={`grid-container .height-auto`}>
|
||||||
Map goes here
|
<div className="grid-row .height-auto">
|
||||||
|
<div className="grid-col-8">
|
||||||
|
<OlMapWrapper />
|
||||||
|
</div>
|
||||||
|
<div className="grid-col-4"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|
3
justice40-frontend/src/pages/index.module.css
Normal file
3
justice40-frontend/src/pages/index.module.css
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.gridContainer {
|
||||||
|
height: 500px;
|
||||||
|
}
|
|
@ -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='© <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
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
|
|
|
@ -7,15 +7,3 @@ $theme-font-path: "../../node_modules/uswds/src/fonts";
|
||||||
|
|
||||||
@import "../../node_modules/uswds/";
|
@import "../../node_modules/uswds/";
|
||||||
@import "../../node_modules/ol/ol.css";
|
@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%;
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue