docker file and parcel
This commit is contained in:
parent
ffdab5ce24
commit
54e70beb0e
9 changed files with 565 additions and 245 deletions
13
Dockerfile
Normal file
13
Dockerfile
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
FROM node
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json .
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
CMD [ "npm", "run", "dev"]
|
||||||
448
package-lock.json
generated
448
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,7 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc -b && vite build",
|
"build": "vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
|
|
@ -13,7 +13,8 @@
|
||||||
"ol": "^10.5.0",
|
"ol": "^10.5.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-router-dom": "^7.5.0"
|
"react-router-dom": "^7.5.0",
|
||||||
|
"vite-plugin-checker": "^0.9.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.21.0",
|
"@eslint/js": "^9.21.0",
|
||||||
|
|
|
||||||
14
src/App.css
14
src/App.css
|
|
@ -15,5 +15,17 @@
|
||||||
|
|
||||||
.coordinates-container {
|
.coordinates-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: -2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ol-popup{
|
||||||
|
position: absolute;
|
||||||
|
background-color: white;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid black;
|
||||||
|
transform: translate(-50%, -100%);
|
||||||
|
pointer-events: none;
|
||||||
|
width: 220px;
|
||||||
|
color: black;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import OpenLayerMap from './components/OpenLayerMap';
|
import OpenLayerMap from './components/OpenLayerMap';
|
||||||
|
import OpenLayerEsri from './components/OpenLayerEsri';
|
||||||
import LegiScanAPI from './components/LegiScanAPI';
|
import LegiScanAPI from './components/LegiScanAPI';
|
||||||
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
|
||||||
|
|
||||||
|
|
@ -11,8 +12,9 @@ function App() {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route exact path="/" element={<OpenLayerMap />} />
|
<Route path="/" element={<OpenLayerMap />} />
|
||||||
<Route exact path="/legi" element={<LegiScanAPI />} />
|
<Route path="/esri" element={<OpenLayerEsri />} />
|
||||||
|
<Route path="/legi" element={<LegiScanAPI />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState, useEffect } from 'react'
|
//import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
async function getBills(data) {
|
async function getBills(data) {
|
||||||
const bill_ids: number[] = [];
|
const bill_ids: number[] = [];
|
||||||
|
|
|
||||||
131
src/components/OpenLayerEsri.tsx
Normal file
131
src/components/OpenLayerEsri.tsx
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
import {useRef} from 'react';
|
||||||
|
import Map from 'ol/Map';
|
||||||
|
import View from 'ol/View';
|
||||||
|
import EsriJSON from 'ol/format/EsriJSON';
|
||||||
|
import TileLayer from 'ol/layer/Tile';
|
||||||
|
import VectorLayer from 'ol/layer/Vector';
|
||||||
|
import {tile as tileStrategy} from 'ol/loadingstrategy';
|
||||||
|
import {fromLonLat} from 'ol/proj';
|
||||||
|
import ImageTile from 'ol/source/ImageTile';
|
||||||
|
import VectorSource from 'ol/source/Vector';
|
||||||
|
import Fill from 'ol/style/Fill';
|
||||||
|
import Stroke from 'ol/style/Stroke';
|
||||||
|
import Style from 'ol/style/Style';
|
||||||
|
import {createXYZ} from 'ol/tilegrid';
|
||||||
|
|
||||||
|
const serviceUrl =
|
||||||
|
'https://services-eu1.arcgis.com/NPIbx47lsIiu2pqz/ArcGIS/rest/services/' +
|
||||||
|
'Neptune_Coastline_Campaign_Open_Data_Land_Use_2014/FeatureServer/';
|
||||||
|
const layer = '0';
|
||||||
|
|
||||||
|
const fillColors = {
|
||||||
|
'Lost To Sea Since 1965': [0, 0, 0, 1],
|
||||||
|
'Urban/Built-up': [104, 104, 104, 1],
|
||||||
|
'Shacks': [115, 76, 0, 1],
|
||||||
|
'Industry': [230, 0, 0, 1],
|
||||||
|
'Wasteland': [230, 0, 0, 1],
|
||||||
|
'Caravans': [0, 112, 255, 0.5],
|
||||||
|
'Defence': [230, 152, 0, 0.5],
|
||||||
|
'Transport': [230, 152, 0, 1],
|
||||||
|
'Open Countryside': [255, 255, 115, 1],
|
||||||
|
'Woodland': [38, 115, 0, 1],
|
||||||
|
'Managed Recreation/Sport': [85, 255, 0, 1],
|
||||||
|
'Amenity Water': [0, 112, 255, 1],
|
||||||
|
'Inland Water': [0, 38, 115, 1],
|
||||||
|
};
|
||||||
|
|
||||||
|
const style = new Style({
|
||||||
|
fill: new Fill(),
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: [0, 0, 0, 1],
|
||||||
|
width: 0.5,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const OpenLayerEsri = () => {
|
||||||
|
const mapDivRef = useRef<HTMLDivElement>(null);
|
||||||
|
const vectorSource = new VectorSource({
|
||||||
|
format: new EsriJSON(),
|
||||||
|
url: function (extent, projection) {
|
||||||
|
// ArcGIS Server only wants the numeric portion of the projection ID.
|
||||||
|
const srid = projection
|
||||||
|
.getCode()
|
||||||
|
.split(/:(?=\d+$)/)
|
||||||
|
.pop();
|
||||||
|
|
||||||
|
const url =
|
||||||
|
serviceUrl +
|
||||||
|
layer +
|
||||||
|
'/query/?f=json&' +
|
||||||
|
'returnGeometry=true&spatialRel=esriSpatialRelIntersects&geometry=' +
|
||||||
|
encodeURIComponent(
|
||||||
|
'{"xmin":' +
|
||||||
|
extent[0] +
|
||||||
|
',"ymin":' +
|
||||||
|
extent[1] +
|
||||||
|
',"xmax":' +
|
||||||
|
extent[2] +
|
||||||
|
',"ymax":' +
|
||||||
|
extent[3] +
|
||||||
|
',"spatialReference":{"wkid":' +
|
||||||
|
srid +
|
||||||
|
'}}',
|
||||||
|
) +
|
||||||
|
'&geometryType=esriGeometryEnvelope&inSR=' +
|
||||||
|
srid +
|
||||||
|
'&outFields=*' +
|
||||||
|
'&outSR=' +
|
||||||
|
srid;
|
||||||
|
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
strategy: tileStrategy(
|
||||||
|
createXYZ({
|
||||||
|
tileSize: 512,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
attributions:
|
||||||
|
'University of Leicester (commissioned by the ' +
|
||||||
|
'<a href="https://www.arcgis.com/home/item.html?id=' +
|
||||||
|
'd5f05b1dc3dd4d76906c421bc1727805">National Trust</a>)',
|
||||||
|
});
|
||||||
|
|
||||||
|
const vector = new VectorLayer({
|
||||||
|
source: vectorSource,
|
||||||
|
style: function (feature) {
|
||||||
|
const classify = feature.get('LU_2014');
|
||||||
|
const color = fillColors[classify] || [0, 0, 0, 0];
|
||||||
|
style.getFill().setColor(color);
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
opacity: 0.7,
|
||||||
|
});
|
||||||
|
|
||||||
|
const raster = new TileLayer({
|
||||||
|
source: new ImageTile({
|
||||||
|
attributions:
|
||||||
|
'Tiles © <a href="https://services.arcgisonline.com/ArcGIS/' +
|
||||||
|
'rest/services/World_Topo_Map/MapServer">ArcGIS</a>',
|
||||||
|
url:
|
||||||
|
'https://server.arcgisonline.com/ArcGIS/rest/services/' +
|
||||||
|
'World_Topo_Map/MapServer/tile/{z}/{y}/{x}',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const map = new Map({
|
||||||
|
layers: [raster,vector],
|
||||||
|
target: mapDivRef.current as HTMLDivElement,
|
||||||
|
view: new View({
|
||||||
|
center: fromLonLat([1.72, 52.4]),
|
||||||
|
zoom: 14,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div ref={mapDivRef} className='map' />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default OpenLayerEsri
|
||||||
|
|
@ -3,129 +3,132 @@ import { Map, View } from 'ol';
|
||||||
|
|
||||||
import 'ol/ol.css';
|
import 'ol/ol.css';
|
||||||
import TileLayer from 'ol/layer/Tile';
|
import TileLayer from 'ol/layer/Tile';
|
||||||
import {tile as tileStrategy} from 'ol/loadingstrategy';
|
import Overlay from 'ol/Overlay'
|
||||||
import {createXYZ} from 'ol/tilegrid';
|
//import Popup from 'ol/Popup'
|
||||||
|
//import {tile as tileStrategy} from 'ol/loadingstrategy';
|
||||||
|
//import {createXYZ} from 'ol/tilegrid';
|
||||||
import { OSM } from 'ol/source';
|
import { OSM } from 'ol/source';
|
||||||
import { Coordinate } from 'ol/coordinate';
|
import { Coordinate } from 'ol/coordinate';
|
||||||
import VectorLayer from "ol/layer/Vector"
|
import VectorLayer from "ol/layer/Vector"
|
||||||
import VectorSource from "ol/source/Vector"
|
import VectorSource from "ol/source/Vector"
|
||||||
import GeoJSON from "ol/format/GeoJSON"
|
import GeoJSON from "ol/format/GeoJSON"
|
||||||
import EsriJSON from "ol/format/EsriJSON"
|
//import EsriJSON from "ol/format/EsriJSON"
|
||||||
import {Style, Icon, Fill, Circle} from "ol/style"
|
import {Style, Icon, Fill, Circle, Stroke} from "ol/style"
|
||||||
import {getCenter} from 'ol/extent';
|
|
||||||
import ImageLayer from 'ol/layer/Image';
|
|
||||||
import ImageArcGISRest from 'ol/source/ImageArcGISRest';
|
|
||||||
|
|
||||||
const OpenLayersMap = () => {
|
const OpenLayersMap = () => {
|
||||||
const mapDivRef = useRef<HTMLDivElement>(null);
|
const mapDivRef = useRef<HTMLDivElement>(null);
|
||||||
|
const popupRef = useRef<HTMLDivElement>(null);
|
||||||
const [olMap, setOlMap] = useState<Map>();
|
|
||||||
|
|
||||||
const [clickedCoordinate, setClickedCoordinate] = useState<Coordinate>();
|
const [clickedCoordinate, setClickedCoordinate] = useState<Coordinate>();
|
||||||
|
|
||||||
const mapRef = useRef()
|
const url_1: any = "https://geo.sandag.org/server/rest/services/Hosted/Address_Points/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&resultType=standard&f=geojson";
|
||||||
|
const url_2: any = "https://geo.sandag.org/server/rest/services/Hosted/Parcels/FeatureServer/0/query?where=1%3D1&outFields=*&returnGeometry=true&resultType=none&f=geojson";
|
||||||
// // read geojson feature
|
|
||||||
// const geoJSONFeatures: any = new GeoJSON().readFeatures(../assets/Address_Points.geojson)
|
|
||||||
|
|
||||||
// // create vector source
|
|
||||||
// const vectorSource: any = new VectorSource({
|
|
||||||
// features: geoJSONFeatures,
|
|
||||||
// })
|
|
||||||
|
|
||||||
// // create vector layer with source
|
|
||||||
// const vectorLayer :any = new VectorLayer({
|
|
||||||
// source: vectorSource,
|
|
||||||
// })
|
|
||||||
const url: any =
|
|
||||||
'https://sampleserver6.arcgisonline.com/ArcGIS/rest/services/' +
|
|
||||||
'USA/MapServer';
|
|
||||||
const url_1: any = "https://geo.sandag.org/server/rest/services/Hosted/Address_Points/FeatureServer/";
|
|
||||||
const layer: any = '0';
|
|
||||||
|
|
||||||
const vectorLayer: any = new VectorLayer({
|
const vectorLayer: any = new VectorLayer({
|
||||||
source: new VectorSource({
|
source: new VectorSource({
|
||||||
format: new GeoJSON(),
|
format: new GeoJSON(),
|
||||||
url: './assets/Address_Points.geojson'
|
url: url_2,
|
||||||
|
style: new Style({
|
||||||
|
fill: new Fill({
|
||||||
|
color: 'red',
|
||||||
|
}),
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'black',
|
||||||
|
width: 2.25
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
|
});
|
||||||
|
const vectorLayer1: any = new VectorLayer({
|
||||||
|
source: new VectorSource({
|
||||||
|
format: new GeoJSON(),
|
||||||
|
url: url_1,
|
||||||
|
attributions: ['Los Angeles GeoHub |']
|
||||||
}),
|
}),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const vectorSource: any = new VectorSource({
|
|
||||||
format: new EsriJSON(),
|
|
||||||
url: function (extent, resolution, projection) {
|
|
||||||
// ArcGIS Server only wants the numeric portion of the projection ID.
|
|
||||||
const srid: any = projection.getCode().split(/:(?=\d+$)/).pop();
|
|
||||||
|
|
||||||
const url =
|
|
||||||
url_1 +
|
|
||||||
layer +
|
|
||||||
'/query/?f=json&' +
|
|
||||||
'returnGeometry=true&spatialRel=esriSpatialRelIntersects&geometry=' +
|
|
||||||
encodeURIComponent(
|
|
||||||
'{"xmin":' +
|
|
||||||
extent[0] +
|
|
||||||
',"ymin":' +
|
|
||||||
extent[1] +
|
|
||||||
',"xmax":' +
|
|
||||||
extent[2] +
|
|
||||||
',"ymax":' +
|
|
||||||
extent[3] +
|
|
||||||
',"spatialReference":{"wkid":' +
|
|
||||||
srid +
|
|
||||||
'}}',
|
|
||||||
) +
|
|
||||||
'&geometryType=esriGeometryEnvelope&inSR=' +
|
|
||||||
srid +
|
|
||||||
'&outFields=*' +
|
|
||||||
'&outSR=' +
|
|
||||||
srid;
|
|
||||||
|
|
||||||
return url;
|
|
||||||
},
|
|
||||||
strategy: tileStrategy(
|
|
||||||
createXYZ({
|
|
||||||
tileSize: 512,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
attributions:
|
|
||||||
'University of Leicester (commissioned by the ' +
|
|
||||||
'<a href="https://www.arcgis.com/home/item.html?id=' +
|
|
||||||
'd5f05b1dc3dd4d76906c421bc1727805">National Trust</a>)',
|
|
||||||
});
|
|
||||||
|
|
||||||
// default view
|
// default view
|
||||||
const def_view: any = new View({
|
|
||||||
center: [0, 0],
|
|
||||||
zoom: 2,
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
const overlay = new Overlay({
|
||||||
|
element: popupRef.current as HTMLDivElement,
|
||||||
|
autoPan: {
|
||||||
|
animation: {
|
||||||
|
duration: 250,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
target: mapDivRef.current as HTMLDivElement,
|
target: mapDivRef.current as HTMLDivElement,
|
||||||
layers: [
|
layers: [
|
||||||
new TileLayer({
|
new TileLayer({
|
||||||
source: new OSM(),
|
source: new OSM(),
|
||||||
}),
|
}),
|
||||||
new ImageLayer({
|
vectorLayer,
|
||||||
source: new ImageArcGISRest({
|
vectorLayer1
|
||||||
ratio: 1,
|
|
||||||
params: {},
|
|
||||||
url: './assets/Address_Points.geojson',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
view: new View({
|
view: new View({
|
||||||
center: [-10997148, 4569099],
|
center: [-13042228, 3857849],
|
||||||
zoom: 4,
|
zoom: 12,
|
||||||
})
|
}),
|
||||||
|
overlays: [overlay],
|
||||||
});
|
});
|
||||||
|
|
||||||
map.on('click', (e) => {
|
map.on('click', (e) => {
|
||||||
setClickedCoordinate(e.coordinate);
|
setClickedCoordinate(e.coordinate);
|
||||||
|
// Get Coordinates of click
|
||||||
|
const coordinate = e.coordinate;
|
||||||
|
//const hdms = toStringHDMS(toLonLat(coordinate));
|
||||||
|
|
||||||
|
const feature = map.forEachFeatureAtPixel(e.pixel, function (feature) {
|
||||||
|
return feature;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Show popup at clicked position
|
||||||
|
overlay.setPosition(coordinate);
|
||||||
|
if(feature)
|
||||||
|
console.log("feature " + JSON.stringify(feature));
|
||||||
|
|
||||||
|
if(feature && feature.get("subname")){
|
||||||
|
if (popupRef.current) {
|
||||||
|
popupRef.current.innerHTML = `<p>You clicked here:</p><code>` +
|
||||||
|
`<p>Parcel</p>` +
|
||||||
|
|
||||||
|
`<p>${feature.get('subname')}</p>` +
|
||||||
|
`<p> Unit Qty ${feature.get('unitqty')}</p>` +
|
||||||
|
`<p>${feature.get('situs_community')} ${feature.get('situs_zip')}</p>` +
|
||||||
|
`<p>bedrooms ${feature.get('bedrooms')} Baths ${feature.get('baths')}</p>` +
|
||||||
|
`</code>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(feature && feature.get('addrsfx')){
|
||||||
|
if (popupRef.current) {
|
||||||
|
popupRef.current.innerHTML = `<p>You clicked here:</p><code>` +
|
||||||
|
`<p>Address Point</p>` +
|
||||||
|
|
||||||
|
`<p>${feature.get('addrname')} ${feature.get('addrsfx')}</p>` +
|
||||||
|
`<p>${feature.get('addrzip')}</p>` +
|
||||||
|
`<p>${feature.get('community')}</p>` +
|
||||||
|
`</code>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (popupRef.current) {
|
||||||
|
popupRef.current.innerHTML = `<p>You clicked here:</p><code>` +
|
||||||
|
`<p>Not a parcel or Address Point</p>` +
|
||||||
|
`</code>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay.setPosition(coordinate)
|
||||||
});
|
});
|
||||||
|
|
||||||
setOlMap(map);
|
|
||||||
|
|
||||||
// fit view to geometry of geojson feature with padding
|
// fit view to geometry of geojson feature with padding
|
||||||
//def_view.fit(geoJSONFeatures[0].getGeometry().getExtent(), { padding: [100, 100, 100, 100]});
|
//def_view.fit(geoJSONFeatures[0].getGeometry().getExtent(), { padding: [100, 100, 100, 100]});
|
||||||
|
|
@ -135,13 +138,13 @@ view: new View({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div ref={mapDivRef} className='map' />
|
<div ref={mapDivRef} className='map'>
|
||||||
|
<div ref={popupRef} className="ol-popup"/>
|
||||||
|
</div>
|
||||||
{clickedCoordinate && (
|
{clickedCoordinate && (
|
||||||
<span className='coordinates-container'>
|
<span className='coordinates-container'>
|
||||||
You clicked at: {clickedCoordinate[0]} /{' '}
|
You clicked at: {clickedCoordinate[0]} /{' '} {clickedCoordinate[1]}
|
||||||
{clickedCoordinate[1]}
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
|
import checker from 'vite-plugin-checker';
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [checker({typescript: false}),react()],
|
||||||
|
server: {
|
||||||
|
allowedHosts: true,
|
||||||
|
host:true,
|
||||||
|
origin: 'http://localhost:5173',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue