Add test layers

dev
Platon Yasev 3 years ago
parent 81b434b6a2
commit 0b46eab446

@ -0,0 +1,27 @@
import { Layer, Source } from "react-map-gl";
import { gridLayer, pointLayer } from "./layers-config";
export const Layers = () => {
return (
<>
<Source
id="grid"
type="vector"
tiles={[
"https://business.spatiality.website/martin/public.service_polygon/{z}/{x}/{y}.pbf",
]}
>
<Layer {...gridLayer} />
</Source>
<Source
id="points"
type="vector"
tiles={[
"https://business.spatiality.website/martin/public.service_point/{z}/{x}/{y}.pbf",
]}
>
<Layer {...pointLayer} />
</Source>
</>
);
};

@ -1,44 +1,52 @@
import maplibregl from "maplibre-gl";
import Map, { Layer, Popup, Source } from "react-map-gl";
import Map from "react-map-gl";
import { useRef, useState } from "react";
import {
clusterCountLayer,
clusterLayer,
unclusteredPointLayer,
} from "../clusters";
import { countoursLayer } from "../vector-tile";
import { NavigateButton } from "../NavigateButton";
import { Sidebar } from "../modules/Sidebar/Sidebar";
import { gridLayer, pointLayer } from "./layers-config";
import { Layers } from "./Layers";
import { MapPopup } from "./Popup";
const MAP_TILER_KEY = "hE7PBueqYiS7hKSYUXP9";
export const MapComponent = () => {
const mapRef = useRef(null);
const [showPopup, setShowPopup] = useState(true);
const [clickedFeature, setClickedFeature] = useState(null);
const [popupCoordinates, setPopupCoordinates] = useState(null);
const onClick = (event) => {
try {
const feature = event.features[0];
if (!feature) return;
const handleClick = (event) => {
if (!event.features) return;
const clusterId = feature.properties.cluster_id;
const feature = event.features[0];
if (!feature) return;
const mapboxSource = mapRef.current.getSource("earthquakes");
const { lng: pointLng, lat: pointLat } = event.lngLat;
mapboxSource.getClusterExpansionZoom(clusterId, (err, zoom) => {
if (err) {
return;
}
if (feature.geometry.type === "Point") {
const coordinates = feature.geometry.coordinates.slice();
while (Math.abs(pointLng - coordinates[0]) > 180) {
coordinates[0] += pointLng > coordinates[0] ? 360 : -360;
}
mapRef.current.easeTo({
center: feature.geometry.coordinates,
zoom,
duration: 500,
});
});
} catch (err) {
console.error(err);
setPopupCoordinates(coordinates);
} else {
setPopupCoordinates([pointLng, pointLat]);
}
setClickedFeature(feature);
};
const handleMouseEnter = (event) => {
const feature = event.features[0];
if (!feature) return;
mapRef.current.getCanvas().style.cursor = "pointer";
};
const handleMouseLeave = (event) => {
const feature = event.features[0];
if (!feature) {
return;
}
mapRef.current.getCanvas().style.cursor = "";
};
return (
@ -52,39 +60,25 @@ export const MapComponent = () => {
zoom: 10,
}}
ref={mapRef}
interactiveLayerIds={[clusterLayer.id]}
onClick={onClick}
interactiveLayerIds={[pointLayer.id, gridLayer.id]}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{showPopup && (
<Popup
longitude={-100}
latitude={40}
anchor="bottom"
onClose={() => setShowPopup(false)}
>
<div style={{ color: "red", fontWeight: "bold" }}>You are here</div>
</Popup>
{clickedFeature && popupCoordinates && (
<MapPopup
lat={popupCoordinates[1]}
lng={popupCoordinates[0]}
feature={clickedFeature}
onClose={() => {
setPopupCoordinates(null);
setClickedFeature(null);
}}
/>
)}
<Source
id="earthquakes"
type="geojson"
data="https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson"
cluster={true}
clusterMaxZoom={14}
clusterRadius={50}
>
<Layer {...clusterLayer} />
<Layer {...clusterCountLayer} />
<Layer {...unclusteredPointLayer} />
</Source>
<Source
id="countours"
type="vector"
url="https://api.maptiler.com/tiles/contours/tiles.json?key=hE7PBueqYiS7hKSYUXP9"
>
<Layer {...countoursLayer} />
</Source>
<NavigateButton />
<Layers />
<Sidebar />
</Map>
);

@ -0,0 +1,17 @@
import { Popup } from "react-map-gl";
export const MapPopup = ({ feature, lat, lng, onClose }) => {
return (
<Popup
longitude={lng}
latitude={lat}
anchor="bottom"
onClose={onClose}
closeOnClick={false}
>
<div style={{ color: "red", fontWeight: "bold" }}>
<pre>{JSON.stringify(feature.properties, null, 2)}</pre>
</div>
</Popup>
);
};

@ -0,0 +1,24 @@
export const pointLayer = {
id: "points",
type: "circle",
source: "points",
"source-layer": "public.service_point",
paint: {
"circle-color": "#da11b2",
"circle-radius": 4,
"circle-stroke-width": 1,
"circle-stroke-color": "#fff",
},
};
export const gridLayer = {
id: "grid",
type: "fill",
source: "grid",
"source-layer": "public.service_polygon",
layout: {},
paint: {
"fill-color": "#26a2a2",
"fill-opacity": 0.2,
},
};

@ -1,18 +0,0 @@
import { useMap } from "react-map-gl";
export function NavigateButton() {
const { current: map } = useMap();
const onClick = () => {
map.flyTo({ center: [-122.4, 37.8] });
};
return (
<button
onClick={onClick}
style={{ position: "absolute", top: 10, left: 10 }}
>
Go
</button>
);
}

@ -1,43 +0,0 @@
export const clusterLayer = {
id: "clusters",
type: "circle",
source: "earthquakes",
filter: ["has", "point_count"],
paint: {
"circle-color": [
"step",
["get", "point_count"],
"#51bbd6",
100,
"#f1f075",
750,
"#f28cb1",
],
"circle-radius": ["step", ["get", "point_count"], 20, 100, 30, 750, 40],
},
};
export const clusterCountLayer = {
id: "cluster-count",
type: "symbol",
source: "earthquakes",
filter: ["has", "point_count"],
layout: {
"text-field": "{point_count_abbreviated}",
"text-font": ["DIN Offc Pro Medium", "Arial Unicode MS Bold"],
"text-size": 12,
},
};
export const unclusteredPointLayer = {
id: "unclustered-point",
type: "circle",
source: "earthquakes",
filter: ["!", ["has", "point_count"]],
paint: {
"circle-color": "#11b4da",
"circle-radius": 4,
"circle-stroke-width": 1,
"circle-stroke-color": "#fff",
},
};

@ -1,3 +1,13 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
.mapboxgl-popup-content,
.maplibregl-popup-content {
@apply bg-white-background shadow-lg rounded-md;
}
.mapboxgl-popup-anchor-bottom .mapboxgl-popup-tip,
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip {
@apply border-t-white-background;
}

@ -16,7 +16,8 @@ const SelectItem = ({ name, isActive, onClick }) => {
type="text"
className={twMerge(
"text-left",
isActive && "bg-blue hover:bg-blue active:bg-blue focus:bg-blue"
isActive &&
"bg-blue hover:bg-blue active:bg-blue focus:bg-blue transition-none"
)}
onClick={onClick}
>

@ -1,5 +1,6 @@
import { TreeSelect } from "antd";
import { useState } from "react";
import { Title } from "../../components/Title";
const { TreeNode } = TreeSelect;
@ -30,25 +31,28 @@ export const RegionSelect = () => {
};
return (
<TreeSelect
showSearch
style={{ width: "100%" }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="Выберите АО или район"
allowClear
treeDefaultExpandAll
onChange={onChange}
>
{mockRegions.map((parent) => {
return (
<TreeNode key={parent.id} value={parent.id} title={parent.name}>
{parent.children?.map((child) => (
<TreeNode key={child.id} value={child.id} title={child.name} />
))}
</TreeNode>
);
})}
</TreeSelect>
<div>
<Title text={"АО / район"} className={"mb-1"} />
<TreeSelect
showSearch
style={{ width: "100%" }}
value={value}
dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="Выберите АО или район"
allowClear
treeDefaultExpandAll
onChange={onChange}
>
{mockRegions.map((parent) => {
return (
<TreeNode key={parent.id} value={parent.id} title={parent.name}>
{parent.children?.map((child) => (
<TreeNode key={child.id} value={child.id} title={child.name} />
))}
</TreeNode>
);
})}
</TreeSelect>
</div>
);
};

@ -10,7 +10,7 @@ export const Sidebar = () => {
<Button
type="text"
icon={<BsChevronLeft className="mr-3" />}
className="flex items-center p-0 pr-1 text-grey mb-2"
className="flex items-center p-0 pr-1 text-grey mb-2 hover:bg-transparent focus:bg-transparent"
>
Настройки
</Button>

@ -1,14 +0,0 @@
export const countoursLayer = {
id: "terrain-data",
type: "line",
source: "contours",
"source-layer": "contour",
layout: {
"line-join": "round",
"line-cap": "round",
},
paint: {
"line-color": "#ff69b4",
"line-width": 1,
},
};
Loading…
Cancel
Save