added editable route

This commit is contained in:
Fedor Katurov 2019-12-30 13:16:35 +07:00
parent 5664291c92
commit fca52df9f5
17 changed files with 282 additions and 11 deletions

View file

@ -19,6 +19,9 @@ import { IStickerPack } from "$constants/stickers";
import { IDialogs } from "$constants/dialogs";
import { IModes } from "$constants/modes";
import { Map } from "$containers/map/Map"
import { TileLayer } from '$containers/map/TileLayer';
type Props = {
sticker: string,
renderer_active: boolean,
@ -49,6 +52,8 @@ const Component = (props: Props) => (
setDialogActive={props.setDialogActive}
/>
<Map />
{ props.renderer_active &&
<Renderer onClick={props.hideRenderer} />
}

View file

@ -0,0 +1,46 @@
import { Map as MapInterface, map } from "leaflet";
import * as React from "react";
import { createPortal } from "react-dom";
import { MapContext } from "$utils/context.ts";
import { TileLayer } from "$containers/map/TileLayer";
import { Route } from "$containers/map/Route";
import { selectMapProvider, selectMapRoute } from "$redux/map/selectors";
import { connect } from "react-redux";
import * as MAP_ACTIONS from "$redux/map/actions";
const mapStateToProps = state => ({
provider: selectMapProvider(state),
route: selectMapRoute(state)
});
const mapDispatchToProps = {
mapSetRoute: MAP_ACTIONS.mapSetRoute
};
type IProps = React.HTMLAttributes<HTMLDivElement> &
ReturnType<typeof mapStateToProps> &
typeof mapDispatchToProps & {};
const MapUnconnected: React.FC<IProps> = ({ provider, route, mapSetRoute }) => {
const ref = React.useRef(null);
const [maps, setMaps] = React.useState<MapInterface>(null);
React.useEffect(() => {
if (!ref.current) return;
setMaps(map(ref.current).setView([55.0153275, 82.9071235], 13));
}, [ref]);
return createPortal(
<div ref={ref}>
<MapContext.Provider value={maps}>
<TileLayer provider={provider} />
<Route route={route} mapSetRoute={mapSetRoute} is_editing />
</MapContext.Provider>
</div>,
document.getElementById("canvas")
);
};
const Map = connect(mapStateToProps, mapDispatchToProps)(MapUnconnected);
export { Map };

View file

@ -0,0 +1,80 @@
import React, {
FC,
useEffect,
memo,
useContext,
useState,
useCallback
} from "react";
import { IMapRoute, ILatLng } from "../../../redux/map/types";
import { MapContext } from "$utils/context";
import { InteractivePoly } from "$modules/InteractivePoly";
import { isMobile } from "$utils/window";
import { LatLng } from "leaflet";
interface IProps {
route: IMapRoute;
is_editing: boolean;
mapSetRoute: (latlngs: ILatLng[]) => void;
}
const Route: FC<IProps> = memo(({ route, is_editing, mapSetRoute }) => {
const [layer, setLayer] = useState<InteractivePoly>(null);
const map = useContext(MapContext);
const onRouteChanged = useCallback(
({ latlngs }) => {
// mapSetRoute(latlngs)
},
[mapSetRoute]
);
useEffect(() => {
if (!layer) return;
layer.on("latlngschange", onRouteChanged);
return () => layer.off("latlngschange", onRouteChanged);
}, [layer, onRouteChanged]);
useEffect(() => {
if (!map) return;
setLayer(
new InteractivePoly([], {
color: "url(#activePathGradient)",
weight: 6,
maxMarkers: isMobile() ? 20 : 100,
smoothFactor: 3,
updateself: false,
})
.addTo(map)
.on("distancechange", console.log)
.on("allvertexhide", console.log)
.on("allvertexshow", console.log)
// .on("latlngschange", console.log)
);
}, [map]);
useEffect(() => {
if (!layer) return;
const points = (route && route.length > 0 && route) || [];
layer.setPoints(points as LatLng[]); // TODO: refactor this
}, [route, layer]);
useEffect(() => {
if (!layer) return;
if (is_editing) {
layer.editor.enable();
} else {
layer.editor.disable();
}
}, [is_editing, layer]);
return null;
});
export { Route };

View file

@ -0,0 +1,40 @@
import * as React from "react";
import { MapContext, TileContext } from "../../../utils/context";
import { TileLayer as TileLayerInterface, tileLayer } from "leaflet";
import { DEFAULT_PROVIDER, PROVIDERS } from "$constants/providers";
import { IMapReducer } from "$redux/map";
type IProps = React.HTMLAttributes<HTMLDivElement> & {
provider: IMapReducer['provider'],
};
const TileLayer: React.FC<IProps> = ({ children, provider }) => {
const [layer, setLayer] = React.useState<TileLayerInterface>(null);
const map = React.useContext(MapContext);
React.useEffect(() => {
if (!map) return;
setLayer(
tileLayer(PROVIDERS[DEFAULT_PROVIDER].url, {
attribution: "Независимое Велосообщество",
maxNativeZoom: 18,
maxZoom: 18
}).addTo(map)
);
}, [map]);
React.useEffect(() => {
if (!layer || !provider) return;
const { url } =
(provider && PROVIDERS[provider] && PROVIDERS[provider]) ||
PROVIDERS[DEFAULT_PROVIDER];
layer.setUrl(url);
}, [layer, provider]);
return <TileContext.Provider value={layer}>{children}</TileContext.Provider>;
};
export { TileLayer };