Add points layer; add filters to layers; colorize layers

dev
Platon Yasev 3 years ago
parent 9f74564319
commit a907802cd3

@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link href="/favicon.ico" rel="icon"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Постаматы by SpatialTeam</title> <title>Постаматы by SpatialTeam</title>
</head> </head>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -3,12 +3,18 @@ import { gridLayer } from "./layers-config";
import { useGridSize } from "../stores/useGridSize"; import { useGridSize } from "../stores/useGridSize";
import { useLayersVisibility } from "../stores/useLayersVisibility"; import { useLayersVisibility } from "../stores/useLayersVisibility";
export const Grid = () => { export const Grid = ({ rate }) => {
const { gridSize } = useGridSize(); const { gridSize } = useGridSize();
const { const {
isVisible: { grid }, isVisible: { grid },
} = useLayersVisibility(); } = useLayersVisibility();
const filter = [
"all",
[">=", ["get", "rate"], rate[0]],
["<=", ["get", "rate"], rate[1]],
];
return ( return (
<> <>
<Source <Source
@ -27,6 +33,7 @@ export const Grid = () => {
...gridLayer.layout, ...gridLayer.layout,
visibility: grid && gridSize === "net3" ? "visible" : "none", visibility: grid && gridSize === "net3" ? "visible" : "none",
}} }}
filter={filter}
/> />
</Source> </Source>
<Source <Source
@ -45,6 +52,7 @@ export const Grid = () => {
...gridLayer.layout, ...gridLayer.layout,
visibility: grid && gridSize === "net4" ? "visible" : "none", visibility: grid && gridSize === "net4" ? "visible" : "none",
}} }}
filter={filter}
/> />
</Source> </Source>
<Source <Source
@ -63,6 +71,7 @@ export const Grid = () => {
...gridLayer.layout, ...gridLayer.layout,
visibility: grid && gridSize === "net5" ? "visible" : "none", visibility: grid && gridSize === "net5" ? "visible" : "none",
}} }}
filter={filter}
/> />
</Source> </Source>
</> </>

@ -1,28 +1,14 @@
import { Grid } from "./Grid"; import { Grid } from "./Grid";
import { useRating } from "../stores/useRating"; import { useRating } from "../stores/useRating";
import { Points } from "./Points";
export const Layers = () => { export const Layers = () => {
const { rate } = useRating(); const { rate } = useRating();
console.log(rate);
return ( return (
<> <>
<Grid /> <Grid rate={rate} />
{/*<Source*/} <Points rate={rate} />
{/* id="points"*/}
{/* type="vector"*/}
{/* tiles={[*/}
{/* "https://property.spatiality.website/public.service_geofeature/{z}/{x}/{y}.pbf",*/}
{/* ]}*/}
{/*>*/}
{/* <Layer*/}
{/* {...pointLayer}*/}
{/* layout={{*/}
{/* ...pointLayer.layout,*/}
{/* visibility: isPointsVisible ? "visible" : "none",*/}
{/* }}*/}
{/* />*/}
{/*</Source>*/}
</> </>
); );
}; };

@ -2,7 +2,7 @@ import maplibregl from "maplibre-gl";
import Map, { useControl } from "react-map-gl"; import Map, { useControl } from "react-map-gl";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { Sidebar } from "../modules/Sidebar/Sidebar"; import { Sidebar } from "../modules/Sidebar/Sidebar";
import { gridLayer, pointLayer } from "./layers-config"; import { pointLayer } from "./layers-config";
import { Layers } from "./Layers"; import { Layers } from "./Layers";
import { MapPopup } from "./Popup"; import { MapPopup } from "./Popup";
import { import {
@ -29,10 +29,18 @@ export const MapComponent = () => {
const [popupCoordinates, setPopupCoordinates] = useState(null); const [popupCoordinates, setPopupCoordinates] = useState(null);
const handleClick = (event) => { const handleClick = (event) => {
if (!event.features) return; if (!event.features) {
setPopupCoordinates(null);
setClickedFeature(null);
return;
}
const feature = event.features[0]; const feature = event.features[0];
if (!feature) return; if (!feature) {
setPopupCoordinates(null);
setClickedFeature(null);
return;
}
const { lng: pointLng, lat: pointLat } = event.lngLat; const { lng: pointLng, lat: pointLat } = event.lngLat;
@ -75,7 +83,7 @@ export const MapComponent = () => {
zoom: 10, zoom: 10,
}} }}
ref={mapRef} ref={mapRef}
interactiveLayerIds={[pointLayer.id, gridLayer.id]} interactiveLayerIds={[pointLayer.id, "grid3", "grid4", "grid5"]}
onClick={handleClick} onClick={handleClick}
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}

@ -0,0 +1,36 @@
import { Layer, Source } from "react-map-gl";
import { pointLayer } from "./layers-config";
import { useLayersVisibility } from "../stores/useLayersVisibility";
import { useActiveTypes } from "../stores/useActiveTypes";
export const Points = ({ rate }) => {
const { isVisible } = useLayersVisibility();
const { activeTypes } = useActiveTypes();
const getFilter = () => {
if (activeTypes.length) {
return ["in", "category", ...activeTypes];
} else {
return ["all"];
}
};
return (
<Source
id="points"
type="vector"
tiles={[
"https://postamates.spatiality.website/martin/public.point5/{z}/{x}/{y}.pbf",
]}
>
<Layer
{...pointLayer}
layout={{
...pointLayer.layout,
visibility: isVisible.points ? "visible" : "none",
}}
filter={getFilter()}
/>
</Source>
);
};

@ -1,11 +1,39 @@
//kiosk - городские киоски
// mfc - многофункциональные центры предоставления государственных и муниципальных услуг
// library - библиотеки
// dk - дома культуры и клубы
// sport - спортивные объекты
const pointColors = {
kiosk: "#112cda",
mfc: "#932301",
library: "#a51eda",
dk: "#e7dd24",
sport: "#138c44",
};
export const pointLayer = { export const pointLayer = {
id: "points", id: "points",
type: "circle", type: "circle",
source: "points", source: "points",
"source-layer": "public.service_point", "source-layer": "public.point5",
layout: {}, layout: {},
paint: { paint: {
"circle-color": "#da11b2", "circle-color": [
"match",
["get", "category"],
"kiosk",
pointColors.kiosk,
"mfc",
pointColors.mfc,
"library",
pointColors.library,
"dk",
pointColors.dk,
"sport",
pointColors.sport,
"black",
],
"circle-radius": 4, "circle-radius": 4,
"circle-stroke-width": 1, "circle-stroke-width": 1,
"circle-stroke-color": "#fff", "circle-stroke-color": "#fff",
@ -16,7 +44,18 @@ export const gridLayer = {
type: "fill", type: "fill",
layout: {}, layout: {},
paint: { paint: {
"fill-color": "#26a2a2", "fill-color": [
"fill-opacity": 0.2, "interpolate",
["linear"],
["get", "rate"],
0,
"rgb(204,34,34)",
5,
"rgb(255,221,52)",
10,
"rgb(30,131,42)",
],
"fill-opacity": 0.3,
"fill-outline-color": "transparent",
}, },
}; };

@ -6,6 +6,22 @@ const Mark = ({ value }) => {
return <span className={"text-grey text-xs"}>{value}</span>; return <span className={"text-grey text-xs"}>{value}</span>;
}; };
const getInitialMarks = (fullRange, value) => {
if (Array.isArray(value)) {
const [min, max] = value;
return {
...fullRange,
[min]: <Mark value={min} />,
[max]: <Mark value={max} />,
};
} else {
return {
...fullRange,
[value]: <Mark value={value} />,
};
}
};
export const SliderComponent = ({ export const SliderComponent = ({
title, title,
value: initialValue, value: initialValue,
@ -13,21 +29,31 @@ export const SliderComponent = ({
onAfterChange, onAfterChange,
min = 0, min = 0,
max = 100, max = 100,
range = false,
}) => { }) => {
const fullRangeMarks = { const fullRangeMarks = {
[min]: <Mark value={min} />, [min]: <Mark value={min} />,
[max]: <Mark value={max} />, [max]: <Mark value={max} />,
}; };
const [value, setValue] = useState(initialValue); const [value, setValue] = useState(initialValue);
const [marks, setMarks] = useState(fullRangeMarks); const [marks, setMarks] = useState(
getInitialMarks(fullRangeMarks, initialValue)
);
const handleAfterChange = (value) => { const handleAfterChange = (value) => {
const [min, max] = value; if (Array.isArray(value)) {
setMarks({ const [min, max] = value;
...fullRangeMarks, setMarks({
[min]: <Mark value={min} />, ...fullRangeMarks,
[max]: <Mark value={max} />, [min]: <Mark value={min} />,
}); [max]: <Mark value={max} />,
});
} else {
setMarks({
...fullRangeMarks,
[value]: <Mark value={value} />,
});
}
onAfterChange?.(value); onAfterChange?.(value);
}; };
@ -41,11 +67,13 @@ export const SliderComponent = ({
<div> <div>
<Title text={title} /> <Title text={title} />
<Slider <Slider
range range={range}
value={value} value={value}
marks={marks} marks={marks}
onChange={handleChange} onChange={handleChange}
onAfterChange={handleAfterChange} onAfterChange={handleAfterChange}
min={min}
max={max}
/> />
</div> </div>
); );

@ -3,10 +3,18 @@ import { twMerge } from "tailwind-merge";
import { Title } from "../../components/Title"; import { Title } from "../../components/Title";
import { useActiveTypes } from "../../stores/useActiveTypes"; import { useActiveTypes } from "../../stores/useActiveTypes";
//kiosk - городские киоски
// mfc - многофункциональные центры предоставления государственных и муниципальных услуг
// library - библиотеки
// dk - дома культуры и клубы
// sport - спортивные объекты
const types = [ const types = [
{ id: "kiosk", name: "Городские киоски" }, { id: "kiosk", name: "Городские киоски" },
{ id: "mfc", name: "МФЦ" }, { id: "mfc", name: "МФЦ" },
{ id: "library", name: "Библиотеки" }, { id: "library", name: "Библиотеки" },
{ id: "dk", name: "Дома культуры и клубы" },
{ id: "sport", name: "Спортивные объекты" },
]; ];
const SelectItem = ({ name, isActive, onClick }) => { const SelectItem = ({ name, isActive, onClick }) => {

@ -1,5 +1,5 @@
import { useRating } from "../../stores/useRating"; import { useRating } from "../../stores/useRating";
import { SliderComponent as Slider } from "../../components/Slider"; import { SliderComponent as Slider } from "../../components/SliderComponent";
export const RatingSlider = () => { export const RatingSlider = () => {
const { rate, setRate } = useRating(); const { rate, setRate } = useRating();
@ -11,6 +11,8 @@ export const RatingSlider = () => {
title={"Востребованность постамата, усл. ед."} title={"Востребованность постамата, усл. ед."}
value={rate} value={rate}
onAfterChange={handleAfterChange} onAfterChange={handleAfterChange}
max={10}
range
/> />
); );
}; };

@ -1,13 +1,13 @@
import { SliderComponent as Slider } from "../../components/Slider"; import { SliderComponent as Slider } from "../../components/SliderComponent";
import { Button } from "antd"; import { Button } from "antd";
export const Settings = () => { export const Settings = () => {
return ( return (
<div className={"space-y-2 min-w-[300px]"}> <div className={"space-y-2 min-w-[300px]"}>
<Slider title={"Количество жителей"} /> <Slider title={"Количество жителей"} value={50} />
<Slider title={"Количество станций метро"} /> <Slider title={"Количество станций метро"} value={50} />
<Slider title={"Количество существующих постаматов"} /> <Slider title={"Количество существующих постаматов"} value={50} />
<Slider title={"Whatever"} /> <Slider title={"Whatever"} value={50} />
<div> <div>
<Button type="primary" block className={"mt-2"}> <Button type="primary" block className={"mt-2"}>
Рассчитать Рассчитать

@ -2,7 +2,7 @@ import create from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
const store = (set) => ({ const store = (set) => ({
gridSize: "net3", gridSize: "net5",
setGridSize: (value) => setGridSize: (value) =>
set((state) => { set((state) => {
state.gridSize = value; state.gridSize = value;

@ -2,7 +2,7 @@ import create from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
const INITIAL_STATE = { const INITIAL_STATE = {
points: true, points: false,
grid: true, grid: true,
}; };

@ -2,7 +2,7 @@ import create from "zustand";
import { immer } from "zustand/middleware/immer"; import { immer } from "zustand/middleware/immer";
const store = (set) => ({ const store = (set) => ({
rate: [0, 100], rate: [0, 10],
setRate: (value) => setRate: (value) =>
set((state) => { set((state) => {
state.rate = value; state.rate = value;

@ -6,7 +6,7 @@ module.exports = {
colors: { colors: {
primary: "#CC2222FF", primary: "#CC2222FF",
blue: "rgba(167,201,236,0.57)", blue: "rgba(167,201,236,0.57)",
"white-background": "rgba(255, 255, 255, 0.8)", "white-background": "rgba(255, 255, 255, 0.9)",
grey: "rgba(0,0, 0, 0.5)", grey: "rgba(0,0, 0, 0.5)",
}, },
}, },

Loading…
Cancel
Save