[maps][xl] - working with swc equals to minify

This commit is contained in:
Luccas Mateus de Medeiros Gomes
2023-07-05 14:32:57 -03:00
parent 9ee4376abf
commit 6e8d5cb091
14 changed files with 5810 additions and 33 deletions

View File

@@ -0,0 +1,84 @@
import React, { useContext, useEffect, useState } from 'react';
export const Controls = ({ children }) => {
return <div>{children}</div>;
};
import { FullScreen, Zoom } from 'ol/control';
import { MapContext } from './Map';
export const FullScreenControl = () => {
const { map } = useContext(MapContext);
useEffect(() => {
if (!map) return;
let fullScreenControl = new FullScreen({
className: 'ml-1 flex flex-col w-8 items-center mt-2',
activeClassName:
'w-full inline-flex justify-center items-center rounded-t-md bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
inactiveClassName:
'inline-flex w-full justify-center items-center rounded-t-md bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
});
let zoomControl = new Zoom({
className: 'ml-1 flex flex-col w-8 items-center',
zoomInClassName:
'inline-flex w-full justify-center items-center bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
zoomOutClassName:
'inline-flex w-full justify-center items-center rounded-b-md bg-white px-2 py-2 text-gray-400 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10 text-sm',
});
map.controls.push(fullScreenControl);
map.controls.push(zoomControl);
return () => {
map.controls.remove(zoomControl);
map.controls.remove(fullScreenControl);
};
}, [map]);
return null;
};
//build a list of checkboxes in react
export const ListOfCheckboxes = ({ layers, shownLayers, setShownLayers }) => {
//layers is an array of url and name
function addLayer(layer) {
setShownLayers([...shownLayers, layer.url]);
}
function removeLayer(layer) {
setShownLayers(shownLayers.filter((l) => l !== layer.url));
}
return (
<div>
<h3 className="mb-4 font-semibold text-gray-900 ">Layers</h3>
<ul className="w-48 text-sm font-medium text-gray-900 bg-white border border-gray-200 rounded-lg ">
{layers.map((layer, index) => (
<li
key={index}
className="w-full border-b border-gray-200 rounded-t-lg "
>
<div className="flex items-center pl-3">
<input
id={layer.name}
type="checkbox"
defaultChecked={shownLayers.includes(layer.url)}
onClick={() =>
shownLayers.includes(layer.url)
? removeLayer(layer)
: addLayer(layer)
}
value={true}
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 focus:ring-2 "
></input>
<label
htmlFor={layer.name}
className="w-full py-3 ml-2 text-sm font-medium text-gray-90"
>
{layer.name}
</label>
</div>
</li>
))}
</ul>
</div>
);
};

View File

@@ -0,0 +1,29 @@
import { useContext, useEffect, useState } from 'react';
import HeatMap from 'ol/layer/Heatmap';
import { MapContext } from './Map';
const HeatMapLayer = ({ source, style, zIndex = 0 }) => {
const { map } = useContext(MapContext);
const [heatMapLayer, setHeatMapLayer] = useState(null);
useEffect(() => {
if (!map) return;
let heatMapLayer = new HeatMap({
source,
style,
blur: parseInt(5, 10),
radius: parseInt(5, 10),
});
map.addLayer(heatMapLayer);
setHeatMapLayer(heatMapLayer);
heatMapLayer.setZIndex(zIndex);
return () => {
if (map) {
map.removeLayer(heatMapLayer);
}
};
}, [map]);
useEffect(() => {
heatMapLayer && heatMapLayer.setZIndex(zIndex);
}, [zIndex]);
return null;
};
export default HeatMapLayer;

View File

@@ -0,0 +1,4 @@
import React from 'react';
export const Layers = ({ children }) => {
return <div>{children}</div>;
};

View File

@@ -0,0 +1,50 @@
import React, { useRef, useState, useEffect } from 'react';
import * as ol from 'ol';
export const MapContext = new React.createContext();
const Map = ({ children, zoom, center, setSelected }) => {
const mapRef = useRef();
const [map, setMap] = useState(null);
// on component mount
useEffect(() => {
let options = {
view: new ol.View({ zoom, center }),
layers: [],
controls: [],
overlays: [],
};
let mapObject = new ol.Map(options);
mapObject.setTarget(mapRef.current);
setMap(mapObject);
return () => mapObject.setTarget(undefined);
}, []);
useEffect(() => {
if (map) {
if (setSelected !== null) {
let selected = null;
map.on('pointermove', function (e) {
map.forEachFeatureAtPixel(e.pixel, function (f) {
selected = f;
return true;
});
if (selected) {
setSelected(selected);
} else {
setSelected(null);
}
});
}
}
}, [map]);
return (
<MapContext.Provider value={{ map }}>
<div ref={mapRef} className="w-full h-[500px]">
{children}
</div>
</MapContext.Provider>
);
};
export default Map;

View File

@@ -0,0 +1,136 @@
import { useEffect, useState } from 'react';
import Map from './Map';
import { Layers } from './Layers';
import { Fill, Icon, Style } from 'ol/style';
import * as olSource from 'ol/source';
import TileLayer from './TileLayer';
import { fromLonLat } from 'ol/proj';
import VectorLayer from './VectorLayer';
import { Vector as VectorSource } from 'ol/source';
import GeoJSON from 'ol/format/GeoJSON';
import KML from 'ol/format/KML';
import { colors } from './colors';
import { FullScreenControl, Controls, ListOfCheckboxes } from './Controls';
import HeatMapLayer from './HeatMapLayer';
function osm() {
return new olSource.OSM();
}
const formats = {
geojson: new GeoJSON(),
kml: new KML(),
};
interface OpenLayersProps {
layers: {
url: string;
name?: string;
format?: string;
heatmap?: boolean;
}[];
center?: [number, number];
zoom?: number;
popup?: (selected: any) => JSX.Element;
}
export function OpenLayers({
layers,
center = [0, 0],
zoom = 1,
popup,
}: OpenLayersProps) {
const [shownLayers, setShownLayers] = useState(
layers.map((layer) => layer.url)
);
const [selected, setSelected] = useState(null);
const [style, setStyle] = useState(null);
useEffect(() => {
const style = new Style({
fill: new Fill({
color: '#eeeeee',
}),
image: new Icon({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
width: 18,
height: 28,
src: 'https://upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Google_Maps_icon_%282020%29.svg/418px-Google_Maps_icon_%282020%29.svg.png?20200218211225',
}),
});
setStyle(style);
}, []);
return (
<div className="relative">
<Map
center={fromLonLat(center)}
zoom={zoom}
setSelected={popup ? setSelected : null}
>
<Layers>
<TileLayer source={osm()} zIndex={0} />
{layers.map((layer, index) =>
!layer.heatmap ? (
<VectorLayer
key={index}
zIndex={shownLayers.includes(layer.url) ? 1 : -1}
source={
new VectorSource({
url: layer.url,
format: layer.format
? formats[layer.format]
: new GeoJSON(),
})
}
style={function (feature) {
const id = feature.getId();
const color = feature.get('COLOR') || colors[id % 1302].hex;
style.getFill().setColor(color);
return style;
}}
/>
) : (
<HeatMapLayer
key={index}
zIndex={shownLayers.includes(layer.url) ? 1 : -1}
source={
new VectorSource({
url: layer.url,
format: layer.format
? formats[layer.format]
: new GeoJSON(),
})
}
style={function (feature) {
const color =
feature.get('COLOR') || colors[feature.ol_uid % 1302].hex;
style.getFill().setColor(color);
return style;
}}
/>
)
)}
</Layers>
{/* add a floating pane that will output the ListOfCheckboxes component using tailwind*/}
<div className="absolute bottom-0 right-0 m-4 p-4 z-50 bg-white rounded-lg shadow-xl">
<ListOfCheckboxes
layers={layers}
shownLayers={shownLayers}
setShownLayers={setShownLayers}
/>
</div>
{popup && selected && (
<div className="absolute bottom-0 left-0 m-4 p-4 z-50 bg-white rounded-lg shadow-xl">
{popup(selected)}
</div>
)}
<Controls>
<FullScreenControl />
</Controls>
</Map>
</div>
);
}

View File

@@ -0,0 +1,23 @@
import { useContext, useEffect } from 'react';
import OLTileLayer from 'ol/layer/Tile';
import { MapContext } from './Map';
const TileLayer = ({ source, zIndex = 0 }) => {
const { map } = useContext(MapContext);
useEffect(() => {
if (!map) return;
let tileLayer = new OLTileLayer({
source,
zIndex,
});
map.addLayer(tileLayer);
tileLayer.setZIndex(zIndex);
return () => {
if (map) {
map.removeLayer(tileLayer);
}
};
}, [map]);
return null;
};
export default TileLayer;

View File

@@ -0,0 +1,33 @@
import { useContext, useEffect, useState } from 'react';
import OLVectorLayer from 'ol/layer/Vector';
import { MapContext } from './Map';
const VectorLayer = ({ source, style, zIndex = 0 }) => {
const { map } = useContext(MapContext);
const [vectorLayer, setVectorLayer] = useState(null);
useEffect(() => {
if (!map) return;
let vectorLayer = new OLVectorLayer({
source,
style,
});
const vectorSource = vectorLayer.getSource();
vectorSource.on('featuresloadend', function () {
vectorSource.getFeatures().forEach((feature, index) => {
feature.setId(index);
});
});
map.addLayer(vectorLayer);
setVectorLayer(vectorLayer);
vectorLayer.setZIndex(zIndex);
return () => {
if (map) {
map.removeLayer(vectorLayer);
}
};
}, [map]);
useEffect(() => {
vectorLayer && vectorLayer.setZIndex(zIndex);
}, [zIndex]);
return null;
};
export default VectorLayer;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
export * from "./components/Table";
export * from "./components/Catalog";
export * from "./components/LineChart";
export * from "./components/Vega";
export * from "./components/VegaLite";
export * from "./components/FlatUiTable";
export * from './components/Table';
export * from './components/Catalog';
export * from './components/LineChart';
export * from './components/Vega';
export * from './components/VegaLite';
export * from './components/FlatUiTable';
export * from './components/OpenLayers/OpenLayers';