Skip to content

Commit

Permalink
feat: ZoomRange utilisant Range de dsfr et possibilité d'avoir un seu…
Browse files Browse the repository at this point in the history
…l des zoom top ou bottom #470 #362
  • Loading branch information
ocruze committed Oct 2, 2024
1 parent 121c311 commit f4a6ef8
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 39 deletions.
2 changes: 0 additions & 2 deletions assets/components/Utils/ExtentMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import { Geometry as EntrepotGeometry } from "../../@types/entrepot";
import olDefaults from "../../data/ol-defaults.json";
import useCapabilities from "../../hooks/useCapabilities";

import "ol/ol.css";

import "geoportal-extensions-openlayers/dist/GpPluginOpenLayers.css";
import "../../sass/components/map-view.scss";
import "../../sass/components/ol.scss";
Expand Down
2 changes: 0 additions & 2 deletions assets/components/Utils/RMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import olDefaults from "../../data/ol-defaults.json";
import useCapabilities from "../../hooks/useCapabilities";
import StyleHelper from "../../modules/Style/StyleHelper";

import "ol/ol.css";

import "geoportal-extensions-openlayers/dist/GpPluginOpenLayers.css";

import "../../sass/components/ol.scss";
Expand Down
1 change: 0 additions & 1 deletion assets/components/Utils/RangeSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ const RangeSlider: FC<RangeSliderProps> = (props) => {
value: v,
label: v.toString(),
}))}
getAriaLabel={() => "Minimum distance"}
value={values}
onChange={(_, newValue) => {
if (!Array.isArray(newValue)) {
Expand Down
151 changes: 139 additions & 12 deletions assets/components/Utils/ZoomRange.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { fr } from "@codegouvfr/react-dsfr";
import Range, { RangeProps } from "@codegouvfr/react-dsfr/Range";
import { cx } from "@codegouvfr/react-dsfr/tools/cx";
import Map from "ol/Map";
import { MapOptions } from "ol/PluggableMap";
import View, { ViewOptions } from "ol/View";
Expand All @@ -7,28 +9,31 @@ import BaseLayer from "ol/layer/Base";
import TileLayer from "ol/layer/Tile";
import { fromLonLat } from "ol/proj";
import WMTS, { optionsFromCapabilities } from "ol/source/WMTS";
import { FC, memo, useCallback, useEffect, useRef } from "react";
import { FC, memo, ReactNode, useCallback, useEffect, useRef } from "react";
import { symToStr } from "tsafe/symToStr";
import { tss } from "tss-react";

import olDefaults from "../../data/ol-defaults.json";
import useCapabilities from "../../hooks/useCapabilities";
import RangeSlider from "./RangeSlider";

import "ol/ol.css";

import "../../sass/components/zoom-range.scss";
import imgMapZoomBottom from "../../img/zoom-range/map-zoom-bottom.png";
import imgMapZoomTop from "../../img/zoom-range/map-zoom-top.png";

type ZoomRangeProps = {
min: number;
max: number;
min: RangeProps["min"];
max: RangeProps["min"];
values: number[];
onChange: (values: number[]) => void;
step?: RangeProps["step"];
center?: number[];
mode?: "top" | "bottom" | "both";
overlayContent?: ReactNode;
};

const ZoomRange: FC<ZoomRangeProps> = (props) => {
const { data: capabilities } = useCapabilities();

const { min, max, values, center = olDefaults.center, onChange } = props;
const { min, max, values, center = olDefaults.center, onChange, step, mode = "both", overlayContent } = props;

// References sur les deux cartes
const leftMapRef = useRef<Map>();
Expand Down Expand Up @@ -112,15 +117,137 @@ const ZoomRange: FC<ZoomRangeProps> = (props) => {
rightMapRef.current?.updateSize();
}, [values]);

const handleChange = useCallback(
(newValue: number, zoomType?: "top" | "bottom") => {
switch (zoomType) {
case "top":
onChange([newValue, values[1]]);
break;
case "bottom":
onChange([values[0], newValue]);
break;
default:
onChange([newValue]);
break;
}
},
[onChange, values]
);

const { classes } = useStyles();

return (
<div className={fr.cx("fr-my-2v")}>
<div className="ui-map-zoom-levels">
<div ref={leftMapTargetRef} className="ui-top-zoom-level" />
<div ref={rightMapTargetRef} className="ui-bottom-zoom-level" />
<div className={fr.cx("fr-grid-row")}>
{(mode === "both" || mode === "top") && (
<div className={fr.cx("fr-col-6", "fr-px-2v")}>
<div ref={leftMapTargetRef} className={cx(classes.map)} />
</div>
)}

{mode !== "both" && (
<div className={cx(fr.cx("fr-col-6", "fr-px-2v"))}>
<div className={cx(classes.falseMapRoot)}>
<img src={mode === "top" ? imgMapZoomBottom : imgMapZoomTop} className={cx(classes.map, classes.falseMapImg)} />
<div className={cx(classes.falseMapOverlay)}>
{overlayContent && <div className={cx(classes.falseMapOverlayContent)}>{overlayContent}</div>}
</div>
</div>
</div>
)}

{(mode === "both" || mode === "bottom") && (
<div className={fr.cx("fr-col-6", "fr-px-2v")}>
<div ref={rightMapTargetRef} className={cx(classes.map)} />
</div>
)}
</div>
<RangeSlider min={min} max={max} values={values} onChange={(newValues) => onChange(newValues)} />
<Range
label=" "
min={min}
max={max}
small={true}
step={step}
{...(() => {
switch (mode) {
case "top":
return {
nativeInputProps: {
value: values?.[0] ?? min,
onChange: (e) => {
handleChange(e.currentTarget.valueAsNumber);
},
},
};
case "bottom":
return {
nativeInputProps: {
value: values?.[0] ?? max,
onChange: (e) => {
handleChange(e.currentTarget.valueAsNumber);
},
},
};
case "both":
return {
double: true,
nativeInputProps: [
{
value: values?.[0] ?? min,
onChange: (e) => {
handleChange(e.currentTarget.valueAsNumber, "top");
},
},
{
value: values?.[1] ?? max,
onChange: (e) => {
handleChange(e.currentTarget.valueAsNumber, "bottom");
},
},
],
};
}
})()}
/>
</div>
);
};

ZoomRange.displayName = symToStr({ ZoomRange });

export default memo(ZoomRange);

const useStyles = tss.withName(ZoomRange.displayName).create(() => ({
map: {
height: "300px",
width: "100%",
},
falseMapRoot: {
position: "relative",
display: "inline-block",
width: "100%",
height: "300px",
},
falseMapImg: {
display: "block",
width: "100%",
height: "300px",
},
falseMapOverlay: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.6)",
textAlign: "center",
},
falseMapOverlayContent: {
backgroundColor: fr.colors.decisions.background.default.grey.default,
color: fr.colors.decisions.text.default.grey.default,
padding: fr.spacing("2v"),
},
}));
4 changes: 2 additions & 2 deletions assets/data/ol-defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"projection": "EPSG:3857",
"zoom": 10,
"zoom_levels": {
"TOP": 0,
"TOP": 1,
"BOTTOM": 18
}
}
}
1 change: 0 additions & 1 deletion assets/entrepot/pages/service/tms/sample/RCSampleMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { UseFormReturn } from "react-hook-form";
import { fr } from "@codegouvfr/react-dsfr";
import Translator from "../../../../../modules/Translator";

import "ol/ol.css";
import "geoportal-extensions-openlayers/dist/GpPluginOpenLayers.css";
import "../../../../../sass/components/map-view.scss";
import "../../../../../sass/components/ol.scss";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { fr } from "@codegouvfr/react-dsfr";
import Accordion from "@codegouvfr/react-dsfr/Accordion";
import Alert from "@codegouvfr/react-dsfr/Alert";
import Button from "@codegouvfr/react-dsfr/Button";
import ButtonsGroup from "@codegouvfr/react-dsfr/ButtonsGroup";
Expand All @@ -8,9 +9,12 @@ import { useQuery } from "@tanstack/react-query";
import { declareComponentKeys } from "i18nifty";
import { FC, useCallback, useState } from "react";

import { Service } from "../../../../@types/app";
import type { Service } from "../../../../@types/app";
import type { ConfigurationWmsVectorDetailsContent } from "../../../../@types/entrepot";
import DatastoreLayout from "../../../../components/Layout/DatastoreLayout";
import LoadingText from "../../../../components/Utils/LoadingText";
import ZoomRange from "../../../../components/Utils/ZoomRange";
import olDefaults from "../../../../data/ol-defaults.json";
import useScrollToTopEffect from "../../../../hooks/useScrollToTopEffect";
import { Translations, useTranslation } from "../../../../i18n/i18n";
import RQKeys from "../../../../modules/entrepot/RQKeys";
Expand All @@ -33,7 +37,7 @@ const PyramidRasterGenerateForm: FC<PyramidRasterGenerateFormProps> = ({ datasto
const { t } = useTranslation("PyramidRasterGenerateForm");
const { t: tCommon } = useTranslation("Common");

const [currentStep, setCurrentStep] = useState(STEPS.TECHNICAL_NAME);
const [currentStep, setCurrentStep] = useState(STEPS.TOP_ZOOM_LEVEL);

const serviceQuery = useQuery<Service, CartesApiException>({
queryKey: RQKeys.datastore_offering(datastoreId, offeringId),
Expand Down Expand Up @@ -65,6 +69,8 @@ const PyramidRasterGenerateForm: FC<PyramidRasterGenerateFormProps> = ({ datasto
/*createServiceMutation, editServiceMutation, trigger, editMode*/
]);

const [levels, setLevels] = useState([5, 15]);

return (
<DatastoreLayout datastoreId={datastoreId} documentTitle={t("title")}>
<h1>{t("title")}</h1>
Expand Down Expand Up @@ -115,6 +121,44 @@ const PyramidRasterGenerateForm: FC<PyramidRasterGenerateFormProps> = ({ datasto
de la carte de gauche. Le zoom maximum sur l’image de droite est fixe et ne peut être modifié. Tous les niveaux intermédiaires seront
générés.`}
</p>

{currentStep === STEPS.TOP_ZOOM_LEVEL &&
(serviceQuery.data?.configuration.type_infos as ConfigurationWmsVectorDetailsContent).used_data?.[0]?.relations.map((rel) => (
<Accordion key={rel.name} label={rel.name} titleAs="h4" defaultExpanded={true}>
<ZoomRange
min={olDefaults.zoom_levels.TOP}
max={olDefaults.zoom_levels.BOTTOM}
values={levels}
onChange={(values) => {
console.log(values);
setLevels((prevLevels) => [values[0], prevLevels[1]]);
}}
step={1}
mode="top"
/>
<ZoomRange
min={olDefaults.zoom_levels.TOP}
max={olDefaults.zoom_levels.BOTTOM}
values={levels}
onChange={(values) => {
console.log(values);
setLevels((prevLevels) => [prevLevels[0], values[0]]);
}}
step={1}
mode="bottom"
/>
<ZoomRange
min={olDefaults.zoom_levels.TOP}
max={olDefaults.zoom_levels.BOTTOM}
values={levels}
onChange={(values) => {
console.log(values);
setLevels(values);
}}
step={1}
/>
</Accordion>
))}
</div>

<ButtonsGroup
Expand Down
Binary file added assets/img/zoom-range/map-zoom-bottom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/zoom-range/map-zoom-top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions assets/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { useApiEspaceCoStore } from "./stores/ApiEspaceCoStore";
import { useAuthStore } from "./stores/AuthStore";
import { useSnackbarStore } from "./stores/SnackbarStore";

import "ol/ol.css";

// en prod
if ((document.getElementById("root") as HTMLDivElement)?.dataset?.appEnv?.toLowerCase() === "prod") {
disableReactDevTools();
Expand Down
17 changes: 0 additions & 17 deletions assets/sass/components/zoom-range.scss

This file was deleted.

0 comments on commit f4a6ef8

Please sign in to comment.