fix(carto): show map UI before loading map styles
This commit is contained in:
parent
022fb04e2b
commit
2a42690388
7 changed files with 45 additions and 40 deletions
|
@ -57,7 +57,8 @@ module.exports = {
|
||||||
'prettier/prettier': 'error',
|
'prettier/prettier': 'error',
|
||||||
'react-hooks/rules-of-hooks': 'error',
|
'react-hooks/rules-of-hooks': 'error',
|
||||||
'react-hooks/exhaustive-deps': 'error',
|
'react-hooks/exhaustive-deps': 'error',
|
||||||
'@typescript-eslint/no-explicit-any': 'error'
|
'@typescript-eslint/no-explicit-any': 'error',
|
||||||
|
'@typescript-eslint/no-unused-vars': 'error'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type { Point } from 'geojson';
|
import { fire } from '@utils';
|
||||||
|
|
||||||
import ComboAdresseSearch from '../../ComboAdresseSearch';
|
import ComboAdresseSearch from '../../ComboAdresseSearch';
|
||||||
import { useFlyTo } from '../../shared/maplibre/hooks';
|
|
||||||
|
|
||||||
export function AddressInput() {
|
export function AddressInput() {
|
||||||
const flyTo = useFlyTo();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
@ -17,9 +14,8 @@ export function AddressInput() {
|
||||||
className="no-margin"
|
className="no-margin"
|
||||||
placeholder="Rechercher une adresse : saisissez au moins 2 caractères"
|
placeholder="Rechercher une adresse : saisissez au moins 2 caractères"
|
||||||
allowInputValues={false}
|
allowInputValues={false}
|
||||||
onChange={(_, result) => {
|
onChange={(_, feature) => {
|
||||||
const geometry = result?.geometry as Point;
|
fire(document, 'map:zoom', { feature });
|
||||||
flyTo(17, geometry.coordinates as [number, number]);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,8 @@ import { useMapLibre } from '../../shared/maplibre/MapLibre';
|
||||||
import {
|
import {
|
||||||
useFitBounds,
|
useFitBounds,
|
||||||
useEvent,
|
useEvent,
|
||||||
useMapEvent
|
useMapEvent,
|
||||||
|
useFlyTo
|
||||||
} from '../../shared/maplibre/hooks';
|
} from '../../shared/maplibre/hooks';
|
||||||
import {
|
import {
|
||||||
filterFeatureCollection,
|
filterFeatureCollection,
|
||||||
|
@ -116,6 +117,7 @@ function useExternalEvents(
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
const fitBounds = useFitBounds();
|
const fitBounds = useFitBounds();
|
||||||
|
const flyTo = useFlyTo();
|
||||||
|
|
||||||
const onFeatureFocus = useCallback(
|
const onFeatureFocus = useCallback(
|
||||||
({ detail }) => {
|
({ detail }) => {
|
||||||
|
@ -132,6 +134,16 @@ function useExternalEvents(
|
||||||
[featureCollection, fitBounds]
|
[featureCollection, fitBounds]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onZoomFocus = useCallback(
|
||||||
|
({ detail }) => {
|
||||||
|
const { feature } = detail;
|
||||||
|
if (feature) {
|
||||||
|
flyTo(17, feature.geometry.coordinates);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[flyTo]
|
||||||
|
);
|
||||||
|
|
||||||
const onFeatureCreate = useCallback(
|
const onFeatureCreate = useCallback(
|
||||||
({ detail }) => {
|
({ detail }) => {
|
||||||
const { geometry, properties } = detail;
|
const { geometry, properties } = detail;
|
||||||
|
@ -181,6 +193,7 @@ function useExternalEvents(
|
||||||
useEvent('map:feature:create', onFeatureCreate);
|
useEvent('map:feature:create', onFeatureCreate);
|
||||||
useEvent('map:feature:update', onFeatureUpdate);
|
useEvent('map:feature:update', onFeatureUpdate);
|
||||||
useEvent('map:feature:delete', onFeatureDelete);
|
useEvent('map:feature:delete', onFeatureDelete);
|
||||||
|
useEvent('map:zoom', onZoomFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
const translations = [
|
const translations = [
|
||||||
|
|
|
@ -5,11 +5,7 @@ import { PlusIcon, LocationMarkerIcon } from '@heroicons/react/outline';
|
||||||
import { useId } from '@reach/auto-id';
|
import { useId } from '@reach/auto-id';
|
||||||
import CoordinateInput from 'react-coordinate-input';
|
import CoordinateInput from 'react-coordinate-input';
|
||||||
|
|
||||||
import { useFlyTo } from '../../shared/maplibre/hooks';
|
|
||||||
|
|
||||||
export function PointInput() {
|
export function PointInput() {
|
||||||
const flyTo = useFlyTo();
|
|
||||||
|
|
||||||
const inputId = useId();
|
const inputId = useId();
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
const [feature, setFeature] = useState<Feature | null>(null);
|
const [feature, setFeature] = useState<Feature | null>(null);
|
||||||
|
@ -60,15 +56,13 @@ export function PointInput() {
|
||||||
setValue(value);
|
setValue(value);
|
||||||
if (dd.length) {
|
if (dd.length) {
|
||||||
const coordinates: [number, number] = [dd[1], dd[0]];
|
const coordinates: [number, number] = [dd[1], dd[0]];
|
||||||
setFeature({
|
const feature = {
|
||||||
type: 'Feature',
|
type: 'Feature' as const,
|
||||||
geometry: {
|
geometry: { type: 'Point' as const, coordinates },
|
||||||
type: 'Point',
|
|
||||||
coordinates
|
|
||||||
},
|
|
||||||
properties: {}
|
properties: {}
|
||||||
});
|
};
|
||||||
flyTo(17, coordinates);
|
setFeature(feature);
|
||||||
|
fire(document, 'map:zoom', { feature });
|
||||||
} else {
|
} else {
|
||||||
setFeature(null);
|
setFeature(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,19 +46,11 @@ export default function MapEditor({
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
{error && <FlashMessage message={error} level="alert" fixed={true} />}
|
{error && <FlashMessage message={error} level="alert" fixed={true} />}
|
||||||
<MapLibre
|
|
||||||
layers={options.layers}
|
<ImportFileInput featureCollection={featureCollection} {...actions} />
|
||||||
header={
|
|
||||||
<>
|
|
||||||
<ImportFileInput
|
|
||||||
featureCollection={featureCollection}
|
|
||||||
{...actions}
|
|
||||||
/>
|
|
||||||
<AddressInput />
|
<AddressInput />
|
||||||
</>
|
|
||||||
}
|
<MapLibre layers={options.layers}>
|
||||||
footer={<PointInput />}
|
|
||||||
>
|
|
||||||
<DrawLayer
|
<DrawLayer
|
||||||
featureCollection={featureCollection}
|
featureCollection={featureCollection}
|
||||||
{...actions}
|
{...actions}
|
||||||
|
@ -86,6 +78,7 @@ export default function MapEditor({
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</MapLibre>
|
</MapLibre>
|
||||||
|
<PointInput />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,8 @@ import {
|
||||||
useFitBounds,
|
useFitBounds,
|
||||||
useEvent,
|
useEvent,
|
||||||
EventHandler,
|
EventHandler,
|
||||||
useMapEvent
|
useMapEvent,
|
||||||
|
useFlyTo
|
||||||
} from '../../shared/maplibre/hooks';
|
} from '../../shared/maplibre/hooks';
|
||||||
import {
|
import {
|
||||||
filterFeatureCollection,
|
filterFeatureCollection,
|
||||||
|
@ -99,6 +100,7 @@ export function GeoJSONLayer({
|
||||||
|
|
||||||
function useExternalEvents(featureCollection: FeatureCollection) {
|
function useExternalEvents(featureCollection: FeatureCollection) {
|
||||||
const fitBounds = useFitBounds();
|
const fitBounds = useFitBounds();
|
||||||
|
const flyTo = useFlyTo();
|
||||||
const onFeatureFocus = useCallback(
|
const onFeatureFocus = useCallback(
|
||||||
({ detail }) => {
|
({ detail }) => {
|
||||||
const { id } = detail;
|
const { id } = detail;
|
||||||
|
@ -109,6 +111,15 @@ function useExternalEvents(featureCollection: FeatureCollection) {
|
||||||
},
|
},
|
||||||
[featureCollection, fitBounds]
|
[featureCollection, fitBounds]
|
||||||
);
|
);
|
||||||
|
const onZoomFocus = useCallback(
|
||||||
|
({ detail }) => {
|
||||||
|
const { feature } = detail;
|
||||||
|
if (feature) {
|
||||||
|
flyTo(17, feature.geometry.coordinates);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[flyTo]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fitBounds(featureCollection.bbox as LngLatBoundsLike);
|
fitBounds(featureCollection.bbox as LngLatBoundsLike);
|
||||||
|
@ -117,6 +128,7 @@ function useExternalEvents(featureCollection: FeatureCollection) {
|
||||||
}, [fitBounds]);
|
}, [fitBounds]);
|
||||||
|
|
||||||
useEvent('map:feature:focus', onFeatureFocus);
|
useEvent('map:feature:focus', onFeatureFocus);
|
||||||
|
useEvent('map:zoom', onZoomFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
function LineStringLayer({
|
function LineStringLayer({
|
||||||
|
|
|
@ -19,8 +19,6 @@ const Context = createContext<{ map?: Map | null }>({});
|
||||||
|
|
||||||
type MapLibreProps = {
|
type MapLibreProps = {
|
||||||
layers: string[];
|
layers: string[];
|
||||||
header?: ReactNode;
|
|
||||||
footer?: ReactNode;
|
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +28,7 @@ export function useMapLibre() {
|
||||||
return context.map;
|
return context.map;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MapLibre({ children, header, footer, layers }: MapLibreProps) {
|
export function MapLibre({ children, layers }: MapLibreProps) {
|
||||||
const isSupported = useMemo(
|
const isSupported = useMemo(
|
||||||
() => maplibre.supported({ failIfMajorPerformanceCaveat: true }) && !isIE(),
|
() => maplibre.supported({ failIfMajorPerformanceCaveat: true }) && !isIE(),
|
||||||
[]
|
[]
|
||||||
|
@ -90,12 +88,10 @@ export function MapLibre({ children, header, footer, layers }: MapLibreProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Context.Provider value={{ map }}>
|
<Context.Provider value={{ map }}>
|
||||||
{map ? header : null}
|
|
||||||
<div ref={containerRef} style={{ height: '500px' }}>
|
<div ref={containerRef} style={{ height: '500px' }}>
|
||||||
<StyleControl styleId={style.id} {...mapStyleProps} />
|
<StyleControl styleId={style.id} {...mapStyleProps} />
|
||||||
{map ? children : null}
|
{map ? children : null}
|
||||||
</div>
|
</div>
|
||||||
{map ? footer : null}
|
|
||||||
</Context.Provider>
|
</Context.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue