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

View file

@ -10,21 +10,40 @@ import { IMapRoute, ILatLng } from "../../../redux/map/types";
import { MapContext } from "$utils/context"; import { MapContext } from "$utils/context";
import { InteractivePoly } from "$modules/InteractivePoly"; import { InteractivePoly } from "$modules/InteractivePoly";
import { isMobile } from "$utils/window"; import { isMobile } from "$utils/window";
import { LatLng } from "leaflet"; import { LatLng, Map } from "leaflet";
interface IProps { interface IProps {
map: Map;
route: IMapRoute; route: IMapRoute;
is_editing: boolean; is_editing: boolean;
mapSetRoute: (latlngs: ILatLng[]) => void; 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 [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( const onRouteChanged = useCallback(
({ latlngs }) => { ({ latlngs }) => {
// mapSetRoute(latlngs) // console.log('THIS!');
mapSetRoute(latlngs)
}, },
[mapSetRoute] [mapSetRoute]
); );
@ -37,28 +56,11 @@ const Route: FC<IProps> = memo(({ route, is_editing, mapSetRoute }) => {
return () => layer.off("latlngschange", onRouteChanged); return () => layer.off("latlngschange", onRouteChanged);
}, [layer, 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(() => { useEffect(() => {
if (!layer) return; if (!layer) return;
console.log('route use effect!')
const points = (route && route.length > 0 && route) || []; const points = (route && route.length > 0 && route) || [];
layer.setPoints(points as LatLng[]); // TODO: refactor this 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 * as React from "react";
import { MapContext, TileContext } from "../../../utils/context"; 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 { DEFAULT_PROVIDER, PROVIDERS } from "$constants/providers";
import { IMapReducer } from "$redux/map"; import { IMapReducer } from "$redux/map";
type IProps = React.HTMLAttributes<HTMLDivElement> & { type IProps = React.HTMLAttributes<HTMLDivElement> & {
provider: IMapReducer['provider'], 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 [layer, setLayer] = React.useState<TileLayerInterface>(null);
const map = React.useContext(MapContext);
React.useEffect(() => { React.useEffect(() => {
if (!map) return; if (!map) return;
@ -35,6 +35,6 @@ const TileLayer: React.FC<IProps> = ({ children, provider }) => {
}, [layer, provider]); }, [layer, provider]);
return <TileContext.Provider value={layer}>{children}</TileContext.Provider>; return <TileContext.Provider value={layer}>{children}</TileContext.Provider>;
}; });
export { TileLayer }; export { TileLayer };

View file

@ -15,23 +15,29 @@ import {
LatLng, LatLng,
LeafletMouseEvent, LeafletMouseEvent,
latLng, latLng,
LatLngLiteral, LatLngLiteral
} from 'leaflet'; } from "leaflet";
import { distKm, distToSegment, getPolyLength, pointInArea } from "$utils/geom"; import { distKm, distToSegment, getPolyLength, pointInArea } from "$utils/geom";
interface InteractivePolylineOptions extends PolylineOptions { interface InteractivePolylineOptions extends PolylineOptions {
maxMarkers?: number, maxMarkers?: number;
constraintsStyle?: PolylineOptions, constraintsStyle?: PolylineOptions;
kmMarksEnabled?: boolean, kmMarksEnabled?: boolean;
kmMarksStep?: number, kmMarksStep?: number;
} }
export class InteractivePoly extends Polyline { export class InteractivePoly extends Polyline {
constructor(latlngs: LatLngExpression[] | LatLngExpression[][], options?: InteractivePolylineOptions) { constructor(
latlngs: LatLngExpression[] | LatLngExpression[][],
options?: InteractivePolylineOptions
) {
super(latlngs, options); super(latlngs, options);
this.constraintsStyle = { ...this.constraintsStyle, ...options.constraintsStyle }; this.constraintsStyle = {
...this.constraintsStyle,
...options.constraintsStyle
};
this.maxMarkers = options.maxMarkers || this.maxMarkers; this.maxMarkers = options.maxMarkers || this.maxMarkers;
this.constrLine = new Polyline([], this.constraintsStyle); this.constrLine = new Polyline([], this.constraintsStyle);
@ -43,36 +49,41 @@ export class InteractivePoly extends Polyline {
this.touchHinter.setLatLngs(latlngs); this.touchHinter.setLatLngs(latlngs);
}; };
setPoints = (latlngs: LatLng[]) => { setPoints = (latlngs: LatLng[], emitEvent = false) => {
this.setLatLngs(latlngs); this.setLatLngs(latlngs);
this.recreateMarkers(); this.recreateMarkers();
this.recalcDistance(); this.recalcDistance();
this.touchHinter.setLatLngs(latlngs); this.touchHinter.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs });
if (emitEvent) {
this.fire("latlngschange", { latlngs });
}
}; };
createHintMarker = (latlng: LatLng): Marker => marker(latlng, { createHintMarker = (latlng: LatLng): Marker =>
draggable: false, marker(latlng, {
icon: divIcon({ draggable: false,
className: 'leaflet-vertex-drag-helper', icon: divIcon({
iconSize: [11, 11], className: "leaflet-vertex-drag-helper",
iconAnchor: [6, 6] iconSize: [11, 11],
}) iconAnchor: [6, 6]
}); })
});
createMarker = (latlng: LatLng): Marker => marker(latlng, { createMarker = (latlng: LatLng): Marker =>
draggable: true, marker(latlng, {
icon: divIcon({ draggable: true,
className: 'leaflet-vertex-icon', icon: divIcon({
iconSize: [11, 11], className: "leaflet-vertex-icon",
iconAnchor: [6, 6] iconSize: [11, 11],
iconAnchor: [6, 6]
})
}) })
}) .on("contextmenu", this.dropMarker)
.on('contextmenu', this.dropMarker) .on("drag", this.onMarkerDrag)
.on('drag', this.onMarkerDrag) .on("dragstart", this.onMarkerDragStart)
.on('dragstart', this.onMarkerDragStart) .on("dragend", this.onMarkerDragEnd)
.on('dragend', this.onMarkerDragEnd) .addTo(this.markerLayer);
.addTo(this.markerLayer);
recreateMarkers = () => { recreateMarkers = () => {
this.clearAllMarkers(); this.clearAllMarkers();
@ -99,14 +110,14 @@ export class InteractivePoly extends Polyline {
if (this._map.hasLayer(this.markerLayer)) return; if (this._map.hasLayer(this.markerLayer)) return;
this._map.addLayer(this.markerLayer); this._map.addLayer(this.markerLayer);
this.fire('allvertexshow'); this.fire("allvertexshow");
}; };
hideAllMarkers = (): void => { hideAllMarkers = (): void => {
if (!this._map.hasLayer(this.markerLayer)) return; if (!this._map.hasLayer(this.markerLayer)) return;
this._map.removeLayer(this.markerLayer); this._map.removeLayer(this.markerLayer);
this.fire('allvertexhide'); this.fire("allvertexhide");
}; };
showVisibleMarkers = (): void => { showVisibleMarkers = (): void => {
@ -115,15 +126,19 @@ export class InteractivePoly extends Polyline {
const northEast = this._map.getBounds().getNorthEast(); const northEast = this._map.getBounds().getNorthEast();
const southWest = this._map.getBounds().getSouthWest(); const southWest = this._map.getBounds().getSouthWest();
const { visible, hidden } = this.markers.reduce((obj, marker) => { const { visible, hidden } = this.markers.reduce(
const { lat, lng } = marker.getLatLng(); (obj, marker) => {
const is_hidden = (lat > northEast.lat || lng > northEast.lng || lat < southWest.lat || lng < southWest.lng); const { lat, lng } = marker.getLatLng();
const is_hidden =
lat > northEast.lat ||
lng > northEast.lng ||
lat < southWest.lat ||
lng < southWest.lng;
return is_hidden return is_hidden
? { ...obj, hidden: [...obj.hidden, marker] } ? { ...obj, hidden: [...obj.hidden, marker] }
: { ...obj, visible: [...obj.visible, marker] } : { ...obj, visible: [...obj.visible, marker] };
},
},
{ visible: [], hidden: [] } { visible: [], hidden: [] }
); );
@ -136,7 +151,8 @@ export class InteractivePoly extends Polyline {
}); });
hidden.forEach(marker => { hidden.forEach(marker => {
if (this.markerLayer.hasLayer(marker)) this.markerLayer.removeLayer(marker); if (this.markerLayer.hasLayer(marker))
this.markerLayer.removeLayer(marker);
}); });
}; };
@ -147,7 +163,7 @@ export class InteractivePoly extends Polyline {
this.stopDragHinting(); this.stopDragHinting();
this.stopDrawing(); this.stopDrawing();
this.touchHinter.removeFrom(this._map); this.touchHinter.removeFrom(this._map);
this.fire('editordisable'); this.fire("editordisable");
}, },
enable: () => { enable: () => {
this.is_editing = true; this.is_editing = true;
@ -155,16 +171,16 @@ export class InteractivePoly extends Polyline {
this.startDragHinting(); this.startDragHinting();
this.touchHinter.addTo(this._map); this.touchHinter.addTo(this._map);
this.fire('editorenable'); this.fire("editorenable");
}, },
continue: () => { continue: () => {
this.is_drawing = true; this.is_drawing = true;
this.drawing_direction = 'forward'; this.drawing_direction = "forward";
this.startDrawing(); this.startDrawing();
}, },
prepend: () => { prepend: () => {
this.is_drawing = true; this.is_drawing = true;
this.drawing_direction = 'backward'; this.drawing_direction = "backward";
this.startDrawing(); this.startDrawing();
} }
}; };
@ -174,7 +190,8 @@ export class InteractivePoly extends Polyline {
}; };
hideDragHint = (): void => { hideDragHint = (): void => {
if (this._map.hasLayer(this.hintMarker)) this._map.removeLayer(this.hintMarker); if (this._map.hasLayer(this.hintMarker))
this._map.removeLayer(this.hintMarker);
}; };
showDragHint = (): void => { showDragHint = (): void => {
@ -182,17 +199,17 @@ export class InteractivePoly extends Polyline {
}; };
startDragHinting = (): void => { startDragHinting = (): void => {
this.touchHinter.on('mousemove', this.moveDragHint); this.touchHinter.on("mousemove", this.moveDragHint);
this.touchHinter.on('mousedown', this.startDragHintMove); this.touchHinter.on("mousedown", this.startDragHintMove);
this.touchHinter.on('mouseover', this.showDragHint); this.touchHinter.on("mouseover", this.showDragHint);
this.touchHinter.on('mouseout', this.hideDragHint); this.touchHinter.on("mouseout", this.hideDragHint);
}; };
stopDragHinting = (): void => { stopDragHinting = (): void => {
this.touchHinter.off('mousemove', this.moveDragHint); this.touchHinter.off("mousemove", this.moveDragHint);
this.touchHinter.off('mousedown', this.startDragHintMove); this.touchHinter.off("mousedown", this.startDragHintMove);
this.touchHinter.off('mouseover', this.showDragHint); this.touchHinter.off("mouseover", this.showDragHint);
this.touchHinter.off('mouseout', this.hideDragHint); this.touchHinter.off("mouseout", this.hideDragHint);
}; };
startDragHintMove = (event: LeafletMouseEvent): void => { startDragHintMove = (event: LeafletMouseEvent): void => {
@ -216,9 +233,9 @@ export class InteractivePoly extends Polyline {
this.is_dragging = true; this.is_dragging = true;
this._map.on('mousemove', this.dragHintMove); this._map.on("mousemove", this.dragHintMove);
this._map.on('mouseup', this.dragHintAddMarker); this._map.on("mouseup", this.dragHintAddMarker);
this._map.on('mouseout', this.stopDragHintMove); this._map.on("mouseout", this.stopDragHintMove);
}; };
stopDragHintMove = (): void => { stopDragHintMove = (): void => {
@ -226,23 +243,28 @@ export class InteractivePoly extends Polyline {
this.constrLine.removeFrom(this._map); this.constrLine.removeFrom(this._map);
this._map.off('mousemove', this.dragHintMove); this._map.off("mousemove", this.dragHintMove);
this._map.off('mouseup', this.dragHintAddMarker); this._map.off("mouseup", this.dragHintAddMarker);
this._map.off('mouseout', this.stopDragHintMove); this._map.off("mouseout", this.stopDragHintMove);
if (this.is_drawing) this.startDrawing(); if (this.is_drawing) this.startDrawing();
setTimeout(() => { this.is_dragging = false; }, 0); setTimeout(() => {
this.is_dragging = false;
}, 0);
}; };
dragHintAddMarker = ({ latlng }: LeafletMouseEvent): void => { dragHintAddMarker = ({ latlng }: LeafletMouseEvent): void => {
this.dragHintChangeDistance(this.hint_prev_marker, latlng); this.dragHintChangeDistance(this.hint_prev_marker, latlng);
this.markers.splice((this.hint_prev_marker + 1), 0, this.createMarker(latlng)); this.markers.splice(
this.hint_prev_marker + 1,
0,
this.createMarker(latlng)
);
this.insertLatLng(latlng, this.hint_prev_marker + 1); this.insertLatLng(latlng, this.hint_prev_marker + 1);
this.hideDragHint(); this.hideDragHint();
this.stopDragHintMove(); this.stopDragHintMove();
}; };
dragHintChangeDistance = (index: number, current: LatLngLiteral): void => { dragHintChangeDistance = (index: number, current: LatLngLiteral): void => {
@ -251,28 +273,30 @@ export class InteractivePoly extends Polyline {
const initial_distance = distKm(prev.getLatLng(), next.getLatLng()); const initial_distance = distKm(prev.getLatLng(), next.getLatLng());
const current_distance = ( const current_distance =
((prev && distKm(prev.getLatLng(), current)) || 0) + ((prev && distKm(prev.getLatLng(), current)) || 0) +
((next && distKm(next.getLatLng(), current)) || 0) ((next && distKm(next.getLatLng(), current)) || 0);
);
this.distance += (current_distance - initial_distance); this.distance += current_distance - initial_distance;
this.fire('distancechange', { distance: this.distance }); this.fire("distancechange", { distance: this.distance });
}; };
dragHintFindNearest = (latlng: LatLng): any => { dragHintFindNearest = (latlng: LatLng): any => {
const latlngs = this.getLatLngs() as LatLng[]; const latlngs = this.getLatLngs() as LatLng[];
const neighbours = latlngs.filter((current, index) => { const neighbours = latlngs
const next = latlngs[index + 1] as LatLng; .filter((current, index) => {
const next = latlngs[index + 1] as LatLng;
return (next && pointInArea(current, next, latlng)); return next && pointInArea(current, next, latlng);
}) })
.map(el => latlngs.indexOf(el)) .map(el => latlngs.indexOf(el))
.sort((a, b) => ( .sort(
distToSegment(latlngs[a], latlngs[a + 1], latlng) - distToSegment(latlngs[b], latlngs[b + 1], latlng) (a, b) =>
)); distToSegment(latlngs[a], latlngs[a + 1], latlng) -
distToSegment(latlngs[b], latlngs[b + 1], latlng)
);
return neighbours.length > 0 ? neighbours[0] : -1; return neighbours.length > 0 ? neighbours[0] : -1;
}; };
@ -284,22 +308,30 @@ export class InteractivePoly extends Polyline {
this.setConstraints([ this.setConstraints([
this.markers[this.hint_prev_marker].getLatLng(), this.markers[this.hint_prev_marker].getLatLng(),
event.latlng, event.latlng,
this.markers[this.hint_prev_marker + 1].getLatLng(), this.markers[this.hint_prev_marker + 1].getLatLng()
]); ]);
}; };
onMarkerDrag = ({ target }: { target: Marker}) => { onMarkerDrag = ({ target }: { target: Marker }) => {
const coords = new Array(0) const coords = new Array(0)
.concat((this.vertex_index > 0 && this.markers[this.vertex_index - 1].getLatLng()) || []) .concat(
(this.vertex_index > 0 &&
this.markers[this.vertex_index - 1].getLatLng()) ||
[]
)
.concat(target.getLatLng()) .concat(target.getLatLng())
.concat((this.vertex_index < (this.markers.length - 1) && this.markers[this.vertex_index + 1].getLatLng()) || []); .concat(
(this.vertex_index < this.markers.length - 1 &&
this.markers[this.vertex_index + 1].getLatLng()) ||
[]
);
this.setConstraints(coords); this.setConstraints(coords);
this.fire('vertexdrag', { index: this.vertex_index, vertex: target }); this.fire("vertexdrag", { index: this.vertex_index, vertex: target });
}; };
onMarkerDragStart = ({ target }: { target: Marker}) => { onMarkerDragStart = ({ target }: { target: Marker }) => {
if (this.is_drawing) { if (this.is_drawing) {
this.stopDrawing(); this.stopDrawing();
this.is_drawing = true; this.is_drawing = true;
@ -312,12 +344,16 @@ export class InteractivePoly extends Polyline {
this.is_dragging = true; this.is_dragging = true;
this.constrLine.addTo(this._map); this.constrLine.addTo(this._map);
this.fire('vertexdragstart', { index: this.vertex_index, vertex: target }); this.fire("vertexdragstart", { index: this.vertex_index, vertex: target });
}; };
onMarkerDragEnd = ({ target }: { target: Marker}): void => { onMarkerDragEnd = ({ target }: { target: Marker }): void => {
const latlngs = this.getLatLngs() as LatLngLiteral[]; const latlngs = this.getLatLngs() as LatLngLiteral[];
this.markerDragChangeDistance(this.vertex_index, latlngs[this.vertex_index], target.getLatLng()); this.markerDragChangeDistance(
this.vertex_index,
latlngs[this.vertex_index],
target.getLatLng()
);
this.replaceLatlng(target.getLatLng(), this.vertex_index); this.replaceLatlng(target.getLatLng(), this.vertex_index);
@ -328,40 +364,43 @@ export class InteractivePoly extends Polyline {
if (this.is_drawing) this.startDrawing(); if (this.is_drawing) this.startDrawing();
this.fire('vertexdragend', { index: this.vertex_index, vertex: target }); this.fire("vertexdragend", { index: this.vertex_index, vertex: target });
}; };
markerDragChangeDistance = (index: number, initial: LatLngLiteral, current: LatLngLiteral): void => { markerDragChangeDistance = (
index: number,
initial: LatLngLiteral,
current: LatLngLiteral
): void => {
const prev = index > 0 ? this.markers[index - 1] : null; const prev = index > 0 ? this.markers[index - 1] : null;
const next = index <= (this.markers.length + 1) ? this.markers[index + 1] : null; const next =
index <= this.markers.length + 1 ? this.markers[index + 1] : null;
const initial_distance = ( const initial_distance =
((prev && distKm(prev.getLatLng(), initial)) || 0) + ((prev && distKm(prev.getLatLng(), initial)) || 0) +
((next && distKm(next.getLatLng(), initial)) || 0) ((next && distKm(next.getLatLng(), initial)) || 0);
);
const current_distance = ( const current_distance =
((prev && distKm(prev.getLatLng(), current)) || 0) + ((prev && distKm(prev.getLatLng(), current)) || 0) +
((next && distKm(next.getLatLng(), current)) || 0) ((next && distKm(next.getLatLng(), current)) || 0);
);
this.distance += (current_distance - initial_distance); this.distance += current_distance - initial_distance;
this.fire('distancechange', { distance: this.distance }); this.fire("distancechange", { distance: this.distance });
}; };
startDrawing = (): void => { startDrawing = (): void => {
this.is_drawing = true; this.is_drawing = true;
this.setConstraints([]); this.setConstraints([]);
this.constrLine.addTo(this._map); this.constrLine.addTo(this._map);
this._map.on('mousemove', this.onDrawingMove); this._map.on("mousemove", this.onDrawingMove);
this._map.on('click', this.onDrawingClick); this._map.on("click", this.onDrawingClick);
}; };
stopDrawing = (): void => { stopDrawing = (): void => {
this.constrLine.removeFrom(this._map); this.constrLine.removeFrom(this._map);
this._map.off('mousemove', this.onDrawingMove); this._map.off("mousemove", this.onDrawingMove);
this._map.off('click', this.onDrawingClick); this._map.off("click", this.onDrawingClick);
this.is_drawing = false; this.is_drawing = false;
}; };
@ -371,11 +410,13 @@ export class InteractivePoly extends Polyline {
return; return;
} }
if (!this._map.hasLayer(this.constrLine)) this._map.addLayer(this.constrLine); if (!this._map.hasLayer(this.constrLine))
this._map.addLayer(this.constrLine);
const marker = this.drawing_direction === 'forward' const marker =
? this.markers[this.markers.length - 1] this.drawing_direction === "forward"
: this.markers[0]; ? this.markers[this.markers.length - 1]
: this.markers[0];
this.setConstraints([latlng, marker.getLatLng()]); this.setConstraints([latlng, marker.getLatLng()]);
}; };
@ -391,7 +432,7 @@ export class InteractivePoly extends Polyline {
this.drawingChangeDistance(latlng); this.drawingChangeDistance(latlng);
if (this.drawing_direction === 'forward') { if (this.drawing_direction === "forward") {
latlngs.push(latlng); latlngs.push(latlng);
this.markers.push(this.createMarker(latlng)); this.markers.push(this.createMarker(latlng));
} else { } else {
@ -400,7 +441,7 @@ export class InteractivePoly extends Polyline {
} }
this.setLatLngs(latlngs); this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs }); this.fire("latlngschange", { latlngs });
this.showVisibleMarkers(); this.showVisibleMarkers();
this.startDrawing(); this.startDrawing();
}; };
@ -410,30 +451,31 @@ export class InteractivePoly extends Polyline {
if (latlngs.length < 1) { if (latlngs.length < 1) {
this.distance = 0; this.distance = 0;
this.fire('distancechange', { distance: this.distance }); this.fire("distancechange", { distance: this.distance });
return; return;
} }
const point = this.drawing_direction === 'forward' const point =
? latlngs[latlngs.length - 1] this.drawing_direction === "forward"
: latlngs[0]; ? latlngs[latlngs.length - 1]
: latlngs[0];
this.distance += distKm(point, latlng); this.distance += distKm(point, latlng);
this.fire('distancechange', { distance: this.distance }); this.fire("distancechange", { distance: this.distance });
}; };
replaceLatlng = (latlng: LatLng, index: number): void => { replaceLatlng = (latlng: LatLng, index: number): void => {
const latlngs = this.getLatLngs() as LatLngLiteral[]; const latlngs = this.getLatLngs() as LatLngLiteral[];
latlngs.splice(index, 1, latlng); latlngs.splice(index, 1, latlng);
this.setLatLngs(latlngs); this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs }); this.fire("latlngschange", { latlngs });
}; };
insertLatLng = (latlng, index): void => { insertLatLng = (latlng, index): void => {
const latlngs = this.getLatLngs(); const latlngs = this.getLatLngs();
latlngs.splice(index, 0, latlng); latlngs.splice(index, 0, latlng);
this.setLatLngs(latlngs); this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs }); this.fire("latlngschange", { latlngs });
}; };
setConstraints = (coords: LatLng[]) => { setConstraints = (coords: LatLng[]) => {
@ -444,7 +486,7 @@ export class InteractivePoly extends Polyline {
const index = this.markers.indexOf(target); const index = this.markers.indexOf(target);
const latlngs = this.getLatLngs(); const latlngs = this.getLatLngs();
if (typeof index === 'undefined' || latlngs.length <= 2) return; if (typeof index === "undefined" || latlngs.length <= 2) return;
this.dropMarkerDistanceChange(index); this.dropMarkerDistanceChange(index);
this._map.removeLayer(this.markers[index]); this._map.removeLayer(this.markers[index]);
@ -452,7 +494,7 @@ export class InteractivePoly extends Polyline {
latlngs.splice(index, 1); latlngs.splice(index, 1);
this.setLatLngs(latlngs); this.setLatLngs(latlngs);
this.fire('latlngschange', { latlngs }); this.fire("latlngschange", { latlngs });
}; };
dropMarkerDistanceChange = (index: number): void => { dropMarkerDistanceChange = (index: number): void => {
@ -460,43 +502,42 @@ export class InteractivePoly extends Polyline {
const prev = index > 0 ? latlngs[index - 1] : null; const prev = index > 0 ? latlngs[index - 1] : null;
const current = latlngs[index]; const current = latlngs[index];
const next = index <= (latlngs.length + 1) ? latlngs[index + 1] : null; const next = index <= latlngs.length + 1 ? latlngs[index + 1] : null;
const initial_distance = ( const initial_distance =
((prev && distKm(prev, current)) || 0) + ((prev && distKm(prev, current)) || 0) +
((next && distKm(next, current)) || 0) ((next && distKm(next, current)) || 0);
);
const current_distance = (prev && next && distKm(prev, next)) || 0; const current_distance = (prev && next && distKm(prev, next)) || 0;
this.distance += (current_distance - initial_distance); this.distance += current_distance - initial_distance;
this.fire('distancechange', { distance: this.distance }); this.fire("distancechange", { distance: this.distance });
}; };
recalcDistance = () => { recalcDistance = () => {
const latlngs = this.getLatLngs() as LatLngLiteral[]; const latlngs = this.getLatLngs() as LatLngLiteral[];
this.distance = getPolyLength(latlngs); this.distance = getPolyLength(latlngs);
this.fire('distancechange', { distance: this.distance }); this.fire("distancechange", { distance: this.distance });
}; };
markers: Marker[] = []; markers: Marker[] = [];
maxMarkers: InteractivePolylineOptions['maxMarkers'] = 2; maxMarkers: InteractivePolylineOptions["maxMarkers"] = 2;
markerLayer: LayerGroup = new LayerGroup(); markerLayer: LayerGroup = new LayerGroup();
constraintsStyle: InteractivePolylineOptions['constraintsStyle'] = { constraintsStyle: InteractivePolylineOptions["constraintsStyle"] = {
weight: 6, weight: 6,
color: 'red', color: "red",
dashArray: '10, 12', dashArray: "10, 12",
opacity: 0.5, opacity: 0.5,
interactive: false, interactive: false
}; };
touchHinter: Polyline = new Polyline([], { touchHinter: Polyline = new Polyline([], {
weight: 24, weight: 24,
smoothFactor: 3, smoothFactor: 3,
className: 'touch-hinter-poly' className: "touch-hinter-poly"
}); });
hintMarker: Marker = this.createHintMarker(latLng({ lat: 0, lng: 0 })); hintMarker: Marker = this.createHintMarker(latLng({ lat: 0, lng: 0 }));
@ -507,28 +548,28 @@ export class InteractivePoly extends Polyline {
is_dragging: boolean = false; is_dragging: boolean = false;
is_drawing: boolean = false; is_drawing: boolean = false;
drawing_direction: 'forward' | 'backward' = 'forward'; drawing_direction: "forward" | "backward" = "forward";
vertex_index?: number = null; vertex_index?: number = null;
hint_prev_marker: number = null; hint_prev_marker: number = null;
distance: number = 0; distance: number = 0;
} }
InteractivePoly.addInitHook(function () { InteractivePoly.addInitHook(function() {
this.once('add', (event) => { this.once("add", event => {
if (event.target instanceof InteractivePoly) { if (event.target instanceof InteractivePoly) {
this.map = event.target._map; this.map = event.target._map;
this.map.on('touch', console.log); this.map.on("touch", console.log);
this.markerLayer.addTo(event.target._map); this.markerLayer.addTo(event.target._map);
this.hintMarker.addTo(event.target._map); this.hintMarker.addTo(event.target._map);
this.constrLine.addTo(event.target._map); this.constrLine.addTo(event.target._map);
this.touchHinter.addTo(event.target._map); this.touchHinter.addTo(event.target._map);
this.map.on('moveend', this.updateMarkers); this.map.on("moveend", this.updateMarkers);
this.on('latlngschange', this.updateTouchHinter); this.on("latlngschange", this.updateTouchHinter);
if (window.innerWidth < 768) { if (window.innerWidth < 768) {
this.touchHinter.setStyle({ weight: 32 }); this.touchHinter.setStyle({ weight: 32 });
@ -536,14 +577,14 @@ InteractivePoly.addInitHook(function () {
} }
}); });
this.once('remove', (event) => { this.once("remove", event => {
if (event.target instanceof InteractivePoly) { if (event.target instanceof InteractivePoly) {
this.markerLayer.removeFrom(this._map); this.markerLayer.removeFrom(this._map);
this.hintMarker.removeFrom(this._map); this.hintMarker.removeFrom(this._map);
this.constrLine.removeFrom(this._map); this.constrLine.removeFrom(this._map);
this.touchHinter.removeFrom(this._map); this.touchHinter.removeFrom(this._map);
this.map.off('moveend', this.updateMarkers); this.map.off("moveend", this.updateMarkers);
} }
}); });
}); });

View file

@ -56,6 +56,7 @@ export class Sticker {
this.deleteSticker = deleteSticker; this.deleteSticker = deleteSticker;
this.lockMapClicks = lockMapClicks; this.lockMapClicks = lockMapClicks;
this.editor = editor; this.editor = editor;
this.element = document.createElement('div');
ReactDOM.render( ReactDOM.render(
<React.Fragment> <React.Fragment>
@ -178,6 +179,8 @@ export class Sticker {
}; };
setAngle = (angle: Props['angle']): void => { setAngle = (angle: Props['angle']): void => {
if (!this.stickerImage) return;
const direction = getLabelDirection(angle); const direction = getLabelDirection(angle);
if (direction !== this.direction) { if (direction !== this.direction) {

View file

@ -2,14 +2,18 @@ import { createReducer } from 'reduxsauce';
import { MAP_HANDLERS } from './handlers'; import { MAP_HANDLERS } from './handlers';
import { DEFAULT_PROVIDER } from '$constants/providers'; import { DEFAULT_PROVIDER } from '$constants/providers';
import { IMapRoute } from './types'; import { IMapRoute } from './types';
import { IStickerDump } from '$modules/Sticker';
export interface IMapReducer { export interface IMapReducer {
provider: string; provider: string;
route: IMapRoute; route: IMapRoute;
stickers: IStickerDump[]
} }
export const MAP_INITIAL_STATE = { export const MAP_INITIAL_STATE = {
provider: DEFAULT_PROVIDER, provider: DEFAULT_PROVIDER,
route: [],
stickers: [],
} }
export const map = createReducer(MAP_INITIAL_STATE, MAP_HANDLERS) export const map = createReducer(MAP_INITIAL_STATE, MAP_HANDLERS)

View file

@ -1,2 +1,5 @@
export const selectMapProvider = state => state.map.provider; import { IState } from "$redux/store";
export const selectMapRoute= state => state.map.route;
export const selectMapProvider = (state: IState) => state.map.provider;
export const selectMapRoute= (state: IState) => state.map.route;
export const selectMapStickers = (state: IState) => state.map.stickers;

View file

@ -157,8 +157,6 @@ function* loadMapSaga(path) {
data: { route, error, random_url } data: { route, error, random_url }
}: Unwrap<typeof getStoredMap> = yield call(getStoredMap, { name: path }); }: Unwrap<typeof getStoredMap> = yield call(getStoredMap, { name: path });
console.log({ route });
if (route && !error) { if (route && !error) {
yield editor.clearAll(); yield editor.clearAll();
yield editor.setData(route); yield editor.setData(route);
@ -172,6 +170,7 @@ function* loadMapSaga(path) {
yield put(mapSet({ yield put(mapSet({
provider: route.provider, provider: route.provider,
route: route.route, route: route.route,
stickers: route.stickers,
})) }))
return { route, random_url }; return { route, random_url };