Calculate rating

dev
Platon Yasev 3 years ago
parent 52d53cceec
commit 8f3bd0eab8

@ -9,8 +9,11 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@turf/bbox": "^6.5.0",
"@turf/helpers": "^6.5.0",
"@watergis/maplibre-gl-export": "^1.3.7", "@watergis/maplibre-gl-export": "^1.3.7",
"antd": "^4.23.6", "antd": "^4.23.6",
"axios": "^1.1.3",
"immer": "^9.0.16", "immer": "^9.0.16",
"mapbox-gl": "npm:empty-npm-package@1.0.0", "mapbox-gl": "npm:empty-npm-package@1.0.0",
"maplibre-gl": "^2.4.0", "maplibre-gl": "^2.4.0",

@ -2,18 +2,60 @@ import { Layer, Source } from "react-map-gl";
import { gridLayer } from "./layers-config"; 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";
import { useFactors } from "../stores/useFactors";
import { useMemo } from "react";
export const Grid = ({ rate }) => { const getWeightedValueExpression = (factor, weight) => {
return ["*", ["to-number", ["get", factor]], weight];
};
export const getRateExpression = (factorWeights) => {
const weightSum = Object.entries(factorWeights).reduce(
(acc, [_factor, weight]) => {
acc += weight;
return acc;
},
0
);
const weightedValuesSum = Object.entries(factorWeights).reduce(
(acc, [factor, weight]) => {
acc.push(getWeightedValueExpression(factor, weight));
return acc;
},
["+"]
);
return ["/", weightedValuesSum, weightSum];
};
export const Grid = ({ rate: rateRange }) => {
const { gridSize } = useGridSize(); const { gridSize } = useGridSize();
const { const {
isVisible: { grid }, isVisible: { grid },
} = useLayersVisibility(); } = useLayersVisibility();
const { factors } = useFactors();
const rate = useMemo(() => getRateExpression(factors), [factors]);
const filter = useMemo(() => {
return ["all", [">=", rate, rateRange[0]], ["<=", rate, rateRange[1]]];
}, [rate, rateRange]);
const filter = [ const paintConfig = {
"all", ...gridLayer.paint,
[">=", ["get", "rate"], rate[0]], "fill-color": [
["<=", ["get", "rate"], rate[1]], "interpolate",
]; ["linear"],
rate,
0,
"rgb(204,34,34)",
25,
"rgb(255,221,52)",
40,
"rgb(30,131,42)",
],
};
return ( return (
<> <>
@ -21,18 +63,19 @@ export const Grid = ({ rate }) => {
id="grid3" id="grid3"
type="vector" type="vector"
tiles={[ tiles={[
`https://postamates.spatiality.website/martin/public.net3/{z}/{x}/{y}.pbf`, `https://postamates.spatiality.website/martin/public.net_3/{z}/{x}/{y}.pbf`,
]} ]}
> >
<Layer <Layer
{...gridLayer} {...gridLayer}
id={"grid3"} id={"grid3"}
source={"grid3"} source={"grid3"}
source-layer={"public.net3"} source-layer={"public.net_3"}
layout={{ layout={{
...gridLayer.layout, ...gridLayer.layout,
visibility: grid && gridSize === "net3" ? "visible" : "none", visibility: grid && gridSize === "net_3" ? "visible" : "none",
}} }}
paint={paintConfig}
filter={filter} filter={filter}
/> />
</Source> </Source>
@ -40,38 +83,40 @@ export const Grid = ({ rate }) => {
id="grid4" id="grid4"
type="vector" type="vector"
tiles={[ tiles={[
`https://postamates.spatiality.website/martin/public.net4/{z}/{x}/{y}.pbf`, `https://postamates.spatiality.website/martin/public.net_4/{z}/{x}/{y}.pbf`,
]} ]}
> >
<Layer <Layer
{...gridLayer} {...gridLayer}
id={"grid4"} id={"grid4"}
source={"grid4"} source={"grid4"}
source-layer={"public.net4"} source-layer={"public.net_4"}
layout={{ layout={{
...gridLayer.layout, ...gridLayer.layout,
visibility: grid && gridSize === "net4" ? "visible" : "none", visibility: grid && gridSize === "net_4" ? "visible" : "none",
}} }}
filter={filter} filter={filter}
paint={paintConfig}
/> />
</Source> </Source>
<Source <Source
id="grid5" id="grid5"
type="vector" type="vector"
tiles={[ tiles={[
`https://postamates.spatiality.website/martin/public.net5/{z}/{x}/{y}.pbf`, `https://postamates.spatiality.website/martin/public.net_5/{z}/{x}/{y}.pbf`,
]} ]}
> >
<Layer <Layer
{...gridLayer} {...gridLayer}
id={"grid5"} id={"grid5"}
source={"grid5"} source={"grid5"}
source-layer={"public.net5"} source-layer={"public.net_5"}
layout={{ layout={{
...gridLayer.layout, ...gridLayer.layout,
visibility: grid && gridSize === "net5" ? "visible" : "none", visibility: grid && gridSize === "net_5" ? "visible" : "none",
}} }}
filter={filter} filter={filter}
paint={paintConfig}
/> />
</Source> </Source>
</> </>

@ -2,7 +2,6 @@ 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 { pointLayer } from "./layers-config";
import { Layers } from "./Layers"; import { Layers } from "./Layers";
import { MapPopup } from "./Popup"; import { MapPopup } from "./Popup";
import { MaplibreExportControl } from "@watergis/maplibre-gl-export"; import { MaplibreExportControl } from "@watergis/maplibre-gl-export";
@ -113,7 +112,14 @@ export const MapComponent = () => {
}} }}
dragRotate={false} dragRotate={false}
ref={mapRef} ref={mapRef}
interactiveLayerIds={[pointLayer.id, "grid3", "grid4", "grid5"]} interactiveLayerIds={[
"point3",
"point4",
"point5",
"grid3",
"grid4",
"grid5",
]}
onClick={handleClick} onClick={handleClick}
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}

@ -2,35 +2,96 @@ import { Layer, Source } from "react-map-gl";
import { pointLayer } from "./layers-config"; import { pointLayer } from "./layers-config";
import { useLayersVisibility } from "../stores/useLayersVisibility"; import { useLayersVisibility } from "../stores/useLayersVisibility";
import { useActiveTypes } from "../stores/useActiveTypes"; import { useActiveTypes } from "../stores/useActiveTypes";
import { useGridSize } from "../stores/useGridSize";
import { useFactors } from "../stores/useFactors";
import { useMemo } from "react";
import { getRateExpression } from "./Grid";
export const Points = ({ rate }) => { export const Points = ({ rate: rateRange }) => {
const { gridSize } = useGridSize();
const { isVisible } = useLayersVisibility(); const { isVisible } = useLayersVisibility();
const { activeTypes } = useActiveTypes(); const { activeTypes } = useActiveTypes();
const { factors } = useFactors();
const getFilter = () => { const rate = useMemo(() => getRateExpression(factors), [factors]);
if (activeTypes.length) {
return ["in", "category", ...activeTypes]; const filter = useMemo(() => {
} else { let result = [
return ["all"]; "all",
} [">=", rate, rateRange[0]],
}; ["<=", rate, rateRange[1]],
];
// if (activeTypes.length) {
// result = ["all", result, ["in", "category", ...activeTypes]];
// }
console.log(result);
return result;
}, [rate, rateRange, activeTypes]);
return ( return (
<Source <>
id="points" <Source
type="vector" id="point3"
tiles={[ type="vector"
"https://postamates.spatiality.website/martin/public.point3/{z}/{x}/{y}.pbf", tiles={[
]} "https://postamates.spatiality.website/martin/public.point3/{z}/{x}/{y}.pbf",
> ]}
<Layer >
{...pointLayer} <Layer
layout={{ {...pointLayer}
...pointLayer.layout, id={"point3"}
visibility: isVisible.points ? "visible" : "none", source={"point3"}
}} source-layer={"public.point3"}
filter={getFilter()} layout={{
/> ...pointLayer.layout,
</Source> visibility:
isVisible.points && gridSize === "net_3" ? "visible" : "none",
}}
filter={filter}
/>
</Source>
<Source
id="point4"
type="vector"
tiles={[
"https://postamates.spatiality.website/martin/public.point4/{z}/{x}/{y}.pbf",
]}
>
<Layer
{...pointLayer}
id={"point4"}
source={"point4"}
source-layer={"public.point4"}
layout={{
...pointLayer.layout,
visibility:
isVisible.points && gridSize === "net_4" ? "visible" : "none",
}}
filter={filter}
/>
</Source>
<Source
id="point5"
type="vector"
tiles={[
"https://postamates.spatiality.website/martin/public.point5/{z}/{x}/{y}.pbf",
]}
>
<Layer
{...pointLayer}
id={"point5"}
source={"point5"}
source-layer={"public.point5"}
layout={{
...pointLayer.layout,
visibility:
isVisible.points && gridSize === "net_5" ? "visible" : "none",
}}
filter={filter}
/>
</Source>
</>
); );
}; };

@ -2,6 +2,26 @@ import { Popup } from "react-map-gl";
import { Col, Row } from "antd"; import { Col, Row } from "antd";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { TYPE_MAPPER } from "../config"; import { TYPE_MAPPER } from "../config";
import { useFactors } from "../stores/useFactors";
const getRate = (featureProps, weights) => {
const weightedSum = Object.entries(weights).reduce(
(acc, [factor, weight]) => {
const value = Number(featureProps[factor]);
const weightedValue = value * weight;
acc += weightedValue;
return acc;
},
0
);
const weightSum = Object.values(weights).reduce((acc, weight) => {
acc += weight;
return acc;
}, 0);
return weightedSum / weightSum;
};
const pointConfig = [ const pointConfig = [
{ {
@ -9,27 +29,34 @@ const pointConfig = [
name: "Тип", name: "Тип",
formatter: (value) => TYPE_MAPPER[value], formatter: (value) => TYPE_MAPPER[value],
}, },
// {
// field: "msk_ao",
// name: "АО",
// },
// {
// field: "msk_rayon",
// name: "Район",
// },
{ {
field: "msk_ao", name: "Востребованность, у.е.",
name: "АО", formatter: (value) => Math.round(value),
},
{
field: "msk_rayon",
name: "Район",
}, },
]; ];
const gridConfig = [ const gridConfig = [
{ {
field: "rate",
name: "Востребованность, у.е.", name: "Востребованность, у.е.",
formatter: (value) => Math.round(value),
}, },
]; ];
export const MapPopup = ({ feature, lat, lng, onClose }) => { export const MapPopup = ({ feature, lat, lng, onClose }) => {
const isPoint = feature.geometry.type === "Point"; const isPoint = feature.geometry.type === "Point";
const config = isPoint ? pointConfig : gridConfig; const config = isPoint ? pointConfig : gridConfig;
const layout = isPoint ? [10, 14] : [20, 4]; const layout = isPoint
? { width: 300, keyCol: 15, valueCol: 9 }
: { width: 250, keyCol: 20, valueCol: 4 };
const { factors } = useFactors();
return ( return (
<Popup <Popup
@ -39,16 +66,18 @@ export const MapPopup = ({ feature, lat, lng, onClose }) => {
onClose={onClose} onClose={onClose}
closeOnClick={false} closeOnClick={false}
> >
<div className={"min-w-[200px]"}> <div className={`min-w-[250px]`}>
{config.map((item) => { {config.map((item) => {
const value = feature.properties[item.field]; const value = item.field
? feature.properties[item.field]
: getRate(feature.properties, factors);
return ( return (
<Row className={twMerge("p-1")} key={item.field}> <Row className={twMerge("p-1")} key={item.field ?? "rate"}>
<Col span={layout[0]} className={"font-semibold"}> <Col span={layout.keyCol} className={"font-semibold"}>
{item.name} {item.name}
</Col> </Col>
<Col span={layout[1]}> <Col span={layout.valueCol}>
{item.formatter ? item.formatter(value) : value} {item.formatter ? item.formatter(value) : value}
</Col> </Col>
</Row> </Row>

@ -13,10 +13,7 @@ const pointColors = {
}; };
export const pointLayer = { export const pointLayer = {
id: "points",
type: "circle", type: "circle",
source: "points",
"source-layer": "public.point3",
layout: {}, layout: {},
paint: { paint: {
"circle-color": [ "circle-color": [
@ -45,18 +42,7 @@ export const gridLayer = {
type: "fill", type: "fill",
layout: {}, layout: {},
paint: { paint: {
"fill-color": [ "fill-opacity": 0.5,
"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", "fill-outline-color": "transparent",
}, },
}; };

@ -30,6 +30,7 @@ export const SliderComponent = ({
min = 0, min = 0,
max = 100, max = 100,
range = false, range = false,
step = 1,
}) => { }) => {
const fullRangeMarks = { const fullRangeMarks = {
[min]: <Mark value={min} />, [min]: <Mark value={min} />,
@ -74,6 +75,7 @@ export const SliderComponent = ({
onAfterChange={handleAfterChange} onAfterChange={handleAfterChange}
min={min} min={min}
max={max} max={max}
step={step}
/> />
</div> </div>
); );

@ -1,3 +1,5 @@
import axios from "axios";
export const TYPE_MAPPER = { export const TYPE_MAPPER = {
kiosk: "Городской киоск", kiosk: "Городской киоск",
mfc: "МФЦ", mfc: "МФЦ",
@ -5,3 +7,28 @@ export const TYPE_MAPPER = {
dk: "Дом культуры и отдыха", dk: "Дом культуры и отдыха",
sport: "Спортивный объект", sport: "Спортивный объект",
}; };
export const factorsNameMapper = {
people: "Численность населения в 2021 г.",
people2025: "Численность населения в 2025 г. (прогноз)",
stops_ot: "Остановки общественного транспорта",
routes_ot: "Маршруты общетвенного транспорта",
in_metro: "Входы в ближайшее метро в месяц",
out_metro: "Выходы из ближайшего метро в месяц",
tc: "Тогровые центры",
empls: "Рабочие места",
walkers: "Трафик населения",
schools: "Школы и детские сады",
parking: "Парковочные места",
pvz: "Пункты выдачи заказов",
gov_place: "Рекомендованные пункты размещения постаматов",
bike_park: "Городская аренда велосипедов, шт.",
products: "Продовольственные магазины",
nonprod: "Непродовольственные магазины",
service: "Пункты оказания бытовых услуг",
vuz: "ВУЗы и техникумы",
};
export const api = axios.create({
baseURL: "https://postamates.spatiality.website",
});

@ -2,6 +2,11 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
.mapboxgl-popup,
.maplibregl-popup {
@apply !max-w-[400px];
}
.mapboxgl-popup-content, .mapboxgl-popup-content,
.maplibregl-popup-content { .maplibregl-popup-content {
@apply bg-grey-light shadow-lg rounded-md; @apply bg-grey-light shadow-lg rounded-md;
@ -13,7 +18,7 @@
} }
.ant-popover-inner { .ant-popover-inner {
@apply bg-white-background rounded-xl; @apply bg-white-background rounded-xl max-h-[calc(100vh-100px)] overflow-y-auto;
} }
.mapboxgl-ctrl-group, .mapboxgl-ctrl-group,

@ -3,9 +3,9 @@ import { Title } from "../../components/Title";
import { useGridSize } from "../../stores/useGridSize"; import { useGridSize } from "../../stores/useGridSize";
const options = [ const options = [
{ label: "3 мин", value: "net3" }, { label: "3 мин", value: "net_3" },
{ label: "4 мин", value: "net4" }, { label: "4 мин", value: "net_4" },
{ label: "5 мин", value: "net5" }, { label: "5 мин", value: "net_5" },
]; ];
export const GridSizeSelect = () => { export const GridSizeSelect = () => {

@ -11,7 +11,7 @@ export const RatingSlider = () => {
title={"Востребованность постамата, у.e."} title={"Востребованность постамата, у.e."}
value={rate} value={rate}
onAfterChange={handleAfterChange} onAfterChange={handleAfterChange}
max={10} max={45}
range range
/> />
); );

@ -1,34 +1,63 @@
import { TreeSelect } from "antd"; import { TreeSelect } from "antd";
import { Title } from "../../components/Title"; import { Title } from "../../components/Title";
import { useRegion } from "../../stores/useRegion"; import { useRegion } from "../../stores/useRegion";
import { useEffect, useMemo, useState } from "react";
import { api } from "../../config";
import { useMap } from "react-map-gl";
import getBbox from "@turf/bbox";
import { polygon as getPolygon } from "@turf/helpers";
const { TreeNode } = TreeSelect; const { TreeNode } = TreeSelect;
const mockRegions = [ const normalizeRegions = (rawRegions) => {
{ if (!rawRegions) return {};
id: "tsao",
name: "Центральный (ЦАО)", return rawRegions.reduce((acc, raw) => {
children: [ acc[`ao-${raw.id}`] = raw;
{ id: "arbat", name: "Арбат" }, if (raw.children) {
{ id: "hamovniki", name: "Хамовники" }, raw.children.forEach((child) => {
], acc[`rayon-${child.id}`] = child;
}, });
{ }
id: "yuao", return acc;
name: "Южный (ЮАО)", }, {});
children: [ };
{ id: "danilovsk", name: "Даниловский" },
{ id: "nagorn", name: "Нагорный" },
],
},
];
export const RegionSelect = () => { export const RegionSelect = () => {
const { current: map } = useMap();
const { region, setRegion } = useRegion(); const { region, setRegion } = useRegion();
const [data, setData] = useState([]);
const normalizedData = useMemo(() => normalizeRegions(data), [data]);
const [loading, setLoading] = useState(false);
useEffect(() => {
const getRegions = async () => {
setLoading(true);
try {
const response = await api.get("/api/ao_and_rayons");
setData(response.data);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
};
getRegions();
}, []);
const onChange = (value) => { const onChange = (value) => {
console.log(value); const selectedRegion = normalizedData[value];
const polygon = getPolygon(selectedRegion.geometry[0]);
const bbox = getBbox(polygon);
setRegion(value); setRegion(value);
map.fitBounds([
[bbox[0], bbox[1]], // southwestern corner of the bounds
[bbox[2], bbox[3]], // northeastern corner of the bounds
]);
}; };
return ( return (
@ -41,16 +70,25 @@ export const RegionSelect = () => {
dropdownStyle={{ maxHeight: 400, overflow: "auto" }} dropdownStyle={{ maxHeight: 400, overflow: "auto" }}
placeholder="Выберите АО или район" placeholder="Выберите АО или район"
allowClear allowClear
treeDefaultExpandAll treeDefaultExpandAll={false}
onChange={onChange} onChange={onChange}
loading={loading}
// treeNodeFilterProp="name" // treeNodeFilterProp="name"
// filterTreeNode={true} // filterTreeNode={true}
> >
{mockRegions.map((parent) => { {data?.map((parent) => {
return ( return (
<TreeNode key={parent.id} value={parent.id} title={parent.name}> <TreeNode
key={`ao-${parent.id}`}
value={`ao-${parent.id}`}
title={parent.name}
>
{parent.children?.map((child) => ( {parent.children?.map((child) => (
<TreeNode key={child.id} value={child.id} title={child.name} /> <TreeNode
key={`rayon-${child.id}`}
value={`rayon-${child.id}`}
title={child.name}
/>
))} ))}
</TreeNode> </TreeNode>
); );

@ -1,13 +1,29 @@
import { SliderComponent as Slider } from "../../components/SliderComponent"; import { SliderComponent as Slider } from "../../components/SliderComponent";
import { Button } from "antd"; import { Button } from "antd";
import { useFactors } from "../../stores/useFactors";
import { factorsNameMapper } from "../../config";
export const Settings = () => { export const Settings = () => {
const { factors, setWeight } = useFactors();
const handleAfterChange = (factor, value) => {
setWeight(factor, value);
};
return ( return (
<div className={"space-y-2 min-w-[300px]"}> <div className={"space-y-2 min-w-[300px]"}>
<Slider title={"Количество жителей"} value={50} /> {Object.entries(factors).map(([field, value]) => {
<Slider title={"Количество станций метро"} value={50} /> return (
<Slider title={"Количество существующих постаматов"} value={50} /> <Slider
<Slider title={"Whatever"} value={50} /> title={factorsNameMapper[field]}
value={value}
key={field}
max={1}
step={0.01}
onAfterChange={(value) => handleAfterChange(field, value)}
/>
);
})}
<div> <div>
<Button type="primary" block className={"mt-2"}> <Button type="primary" block className={"mt-2"}>
Рассчитать Рассчитать

@ -10,7 +10,7 @@ import { Settings } from "./Settings";
export const Sidebar = () => { export const Sidebar = () => {
return ( return (
<div className="absolute top-[10px] right-[10px] bg-white-background w-[300px] rounded-xl p-3"> <div className="absolute top-[10px] right-[10px] bg-white-background w-[300px] rounded-xl p-3 max-h-[calc(100vh-30px)] overflow-y-auto">
<Popover <Popover
placement="leftTop" placement="leftTop"
title={"Веса факторов"} title={"Веса факторов"}

@ -0,0 +1,20 @@
import create from "zustand";
import { immer } from "zustand/middleware/immer";
import { factorsNameMapper } from "../config";
const DEFAULT_WEIGHT = 0.5;
const INITIAL_STATE = Object.keys(factorsNameMapper).reduce((acc, field) => {
acc[field] = DEFAULT_WEIGHT;
return acc;
}, {});
const store = (set) => ({
factors: INITIAL_STATE,
setWeight: (factor, value) =>
set((state) => {
state.factors[factor] = value;
}),
});
export const useFactors = create(immer(store));

@ -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: "net5", gridSize: "net_5",
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 store = (set) => ({ const store = (set) => ({
rate: [0, 10], rate: [0, 45],
setRate: (value) => setRate: (value) =>
set((state) => { set((state) => {
state.rate = value; state.rate = value;

@ -422,6 +422,26 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@turf/bbox@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/bbox/-/bbox-6.5.0.tgz#bec30a744019eae420dac9ea46fb75caa44d8dc5"
integrity sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==
dependencies:
"@turf/helpers" "^6.5.0"
"@turf/meta" "^6.5.0"
"@turf/helpers@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/helpers/-/helpers-6.5.0.tgz#f79af094bd6b8ce7ed2bd3e089a8493ee6cae82e"
integrity sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==
"@turf/meta@^6.5.0":
version "6.5.0"
resolved "https://registry.yarnpkg.com/@turf/meta/-/meta-6.5.0.tgz#b725c3653c9f432133eaa04d3421f7e51e0418ca"
integrity sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==
dependencies:
"@turf/helpers" "^6.5.0"
"@types/geojson@*", "@types/geojson@^7946.0.10": "@types/geojson@*", "@types/geojson@^7946.0.10":
version "7946.0.10" version "7946.0.10"
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249" resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.10.tgz#6dfbf5ea17142f7f9a043809f1cd4c448cb68249"
@ -677,6 +697,15 @@ autoprefixer@^10.4.13:
picocolors "^1.0.0" picocolors "^1.0.0"
postcss-value-parser "^4.2.0" postcss-value-parser "^4.2.0"
axios@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.1.3.tgz#8274250dada2edf53814ed7db644b9c2866c1e35"
integrity sha512-00tXVRwKx/FZr/IDVFt4C+f9FYairX517WoGCL6dpOntqLkZofjhu43F/Xl44UOpqa+9sLFDrG/XAnFsUYgkDA==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
balanced-match@^1.0.0: balanced-match@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@ -1242,6 +1271,11 @@ fill-range@^7.0.1:
dependencies: dependencies:
to-regex-range "^5.0.1" to-regex-range "^5.0.1"
follow-redirects@^1.15.0:
version "1.15.2"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
form-data@^4.0.0: form-data@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
@ -1994,6 +2028,11 @@ protocol-buffers-schema@^3.3.1:
resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03" resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03"
integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw== integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
prr@~1.0.1: prr@~1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"

Loading…
Cancel
Save