stickers stops dragging

This commit is contained in:
Fedor Katurov 2019-12-30 15:07:59 +07:00
parent fca52df9f5
commit 58eefd5670
10 changed files with 388 additions and 175 deletions

View file

@ -2,15 +2,18 @@ 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 { selectMapProvider, selectMapRoute, selectMapStickers } from "$redux/map/selectors";
import { connect } from "react-redux";
import * as MAP_ACTIONS from "$redux/map/actions";
import { Route } from "$containers/map/Route";
import { TileLayer } from "$containers/map/TileLayer";
import { Stickers } from "$containers/map/Stickers";
const mapStateToProps = state => ({
provider: selectMapProvider(state),
route: selectMapRoute(state)
route: selectMapRoute(state),
stickers: selectMapStickers(state),
});
const mapDispatchToProps = {
@ -21,7 +24,7 @@ type IProps = React.HTMLAttributes<HTMLDivElement> &
ReturnType<typeof mapStateToProps> &
typeof mapDispatchToProps & {};
const MapUnconnected: React.FC<IProps> = ({ provider, route, mapSetRoute }) => {
const MapUnconnected: React.FC<IProps> = ({ provider, route, mapSetRoute, stickers }) => {
const ref = React.useRef(null);
const [maps, setMaps] = React.useState<MapInterface>(null);
@ -31,12 +34,13 @@ const MapUnconnected: React.FC<IProps> = ({ provider, route, mapSetRoute }) => {
setMaps(map(ref.current).setView([55.0153275, 82.9071235], 13));
}, [ref]);
// console.log('RERENDER!');
return createPortal(
<div ref={ref}>
<MapContext.Provider value={maps}>
<TileLayer provider={provider} />
<Route route={route} mapSetRoute={mapSetRoute} is_editing />
</MapContext.Provider>
<TileLayer provider={provider} map={maps} />
<Route route={route} mapSetRoute={mapSetRoute} map={maps} is_editing />
<Stickers stickers={stickers} map={maps} is_editing />
</div>,
document.getElementById("canvas")
);

View file

@ -10,21 +10,40 @@ 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";
import { LatLng, Map } from "leaflet";
interface IProps {
map: Map;
route: IMapRoute;
is_editing: boolean;
mapSetRoute: (latlngs: ILatLng[]) => void;
}
const Route: FC<IProps> = memo(({ route, is_editing, mapSetRoute }) => {
const Route: FC<IProps> = memo(({ route, is_editing, mapSetRoute, map }) => {
const [layer, setLayer] = useState<InteractivePoly>(null);
const map = useContext(MapContext);
useEffect(() => {
if (!map) return;
setLayer(
new InteractivePoly([], {
color: "url(#activePathGradient)",
weight: 6,
maxMarkers: isMobile() ? 20 : 100,
smoothFactor: 3,
})
.addTo(map)
// .on("distancechange", console.log)
// .on("allvertexhide", console.log)
// .on("allvertexshow", console.log)
);
}, [map]);
const onRouteChanged = useCallback(
({ latlngs }) => {
// mapSetRoute(latlngs)
// console.log('THIS!');
mapSetRoute(latlngs)
},
[mapSetRoute]
);
@ -37,28 +56,11 @@ const Route: FC<IProps> = memo(({ route, is_editing, mapSetRoute }) => {
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;
console.log('route use effect!')
const points = (route && route.length > 0 && route) || [];
layer.setPoints(points as LatLng[]); // TODO: refactor this

View file

@ -0,0 +1,118 @@
import * as React from "react";
import { Map, marker, Marker } from "leaflet";
import { IStickerDump, Sticker as StickerComponent } from "$modules/Sticker";
import { STICKERS } from "$constants/stickers";
import { StickerDesc } from "$components/StickerDesc";
import classNames from "classnames";
import { DomMarker } from "$utils/DomMarker";
import { createPortal } from "react-dom";
interface IProps {
map: Map;
sticker: IStickerDump;
}
const preventPropagation = (e): void => {
if (!e || !e.stopPropagation) return;
e.stopPropagation();
e.preventDefault();
};
const getX = e =>
e.touches && e.touches.length > 0
? { pageX: e.touches[0].pageX, pageY: e.touches[0].pageY }
: { pageX: e.pageX, pageY: e.pageY };
const Sticker: React.FC<IProps> = ({ map, sticker }) => {
const [layer, setLayer] = React.useState<Marker>(null);
const [dragging, setDragging] = React.useState(false);
const stickerArrow = React.useRef(null);
const stickerImage = React.useRef(null);
const onDragStart = React.useCallback(() => {
layer.dragging.disable();
map.dragging.disable();
setDragging(true);
}, [setDragging, layer, map]);
const onDragStop = React.useCallback(() => {
layer.dragging.enable();
map.dragging.enable();
setDragging(false);
}, [setDragging, layer, map]);
const onDrag = React.useCallback(event => {
// event.stopPrapagation();
// console.log("drag")
}, []);
const onDelete = console.log;
const setText = console.log;
const direction = React.useMemo(() => "left", [sticker.angle]);
const element = React.useMemo(() => document.createElement("div"), []);
React.useEffect(() => {
if (dragging) {
document.addEventListener("mousemove", onDrag);
document.addEventListener("mouseUp", onDragStop);
}
return () => document.removeEventListener("mousemove", onDrag);
}, [dragging, onDrag]);
React.useEffect(() => {
if (!map) return;
const icon = new DomMarker({
element,
className: "sticker-container"
});
const item = marker(sticker.latlng, { icon, draggable: true }).addTo(map);
setLayer(item);
return () => item.removeFrom(map);
}, [element, map, sticker]);
return createPortal(
<React.Fragment>
<div className="sticker-arrow" ref={stickerArrow} />
<div
className={classNames(`sticker-label ${direction}`, {})}
ref={stickerImage}
>
<StickerDesc value={sticker.text} onChange={setText} />
<div
className="sticker-image"
style={{
backgroundImage: `url('${STICKERS[sticker.set].url}`,
backgroundPosition: `${-STICKERS[sticker.set].layers[
sticker.sticker
].off * 72} 50%`
}}
onMouseDown={onDragStart}
onMouseUp={onDragStop}
onTouchStart={onDragStart}
onTouchEnd={onDragStop}
/>
<div
className="sticker-delete"
onMouseDown={onDelete}
onTouchStart={onDelete}
/>
</div>
</React.Fragment>,
element
);
};
export { Sticker };

View file

@ -0,0 +1,39 @@
import * as React from "react";
import { IStickerDump } from "$modules/Sticker";
import { Layer, FeatureGroup, Map } from "leaflet";
import { MapContext } from "$utils/context";
import { Sticker } from "$containers/map/Sticker";
interface IProps {
stickers: IStickerDump[];
is_editing: boolean;
map: Map;
}
// const { FC, useContext, useState, useEffect } = React;
const Stickers: React.FC<IProps> = React.memo(({ stickers, is_editing, map }) => {
const [layer, setLayer] = React.useState<FeatureGroup>(null);
React.useEffect(() => {
if (!map) return;
setLayer(new FeatureGroup().addTo(map));
}, [map]);
return (
<div>
{layer &&
stickers.map((sticker, index) => (
<Sticker
map={map}
sticker={sticker}
key={`${sticker.set}.${sticker.sticker}.${index}`}
/>
))}
</div>
);
// return null;
});
export { Stickers };

View file

@ -1,16 +1,16 @@
import * as React from "react";
import { MapContext, TileContext } from "../../../utils/context";
import { TileLayer as TileLayerInterface, tileLayer } from "leaflet";
import { TileLayer as TileLayerInterface, tileLayer, Map } from "leaflet";
import { DEFAULT_PROVIDER, PROVIDERS } from "$constants/providers";
import { IMapReducer } from "$redux/map";
type IProps = React.HTMLAttributes<HTMLDivElement> & {
provider: IMapReducer['provider'],
map: Map,
};
const TileLayer: React.FC<IProps> = ({ children, provider }) => {
const TileLayer: React.FC<IProps> = React.memo(({ children, provider, map }) => {
const [layer, setLayer] = React.useState<TileLayerInterface>(null);
const map = React.useContext(MapContext);
React.useEffect(() => {
if (!map) return;
@ -35,6 +35,6 @@ const TileLayer: React.FC<IProps> = ({ children, provider }) => {
}, [layer, provider]);
return <TileContext.Provider value={layer}>{children}</TileContext.Provider>;
};
});
export { TileLayer };