mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 19:16:41 +07:00
removed all modules
This commit is contained in:
parent
aa8fd14517
commit
0c321f2bb3
21 changed files with 677 additions and 77 deletions
|
@ -1,65 +0,0 @@
|
|||
import { LatLngLiteral, LayerGroup, Map } from "leaflet";
|
||||
import { arrowClusterIcon, createArrow } from "$utils/arrow";
|
||||
import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js';
|
||||
import { angleBetweenPoints, dist2, middleCoord } from "$utils/geom";
|
||||
|
||||
class Component extends LayerGroup {
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
setLatLngs = (latlngs: LatLngLiteral[]): void => {
|
||||
if (!this.map) return;
|
||||
|
||||
this.arrowLayer.clearLayers();
|
||||
|
||||
if (latlngs.length === 0) return;
|
||||
|
||||
const midpoints = latlngs.reduce((res, latlng, i) => (
|
||||
latlngs[i + 1] && dist2(latlngs[i], latlngs[i + 1]) > 0.00005
|
||||
? [
|
||||
...res,
|
||||
{
|
||||
latlng: middleCoord(latlngs[i], latlngs[i + 1]),
|
||||
angle: angleBetweenPoints(
|
||||
this.map.latLngToContainerPoint(latlngs[i]),
|
||||
this.map.latLngToContainerPoint(latlngs[i + 1])
|
||||
),
|
||||
}
|
||||
]
|
||||
: res
|
||||
), []);
|
||||
|
||||
midpoints.forEach(({ latlng, angle }) => (
|
||||
this.arrowLayer.addLayer(createArrow(latlng, angle))
|
||||
));
|
||||
};
|
||||
|
||||
map: Map;
|
||||
arrowLayer: MarkerClusterGroup = new MarkerClusterGroup({
|
||||
spiderfyOnMaxZoom: false,
|
||||
showCoverageOnHover: false,
|
||||
zoomToBoundsOnClick: false,
|
||||
animate: false,
|
||||
maxClusterRadius: 120,
|
||||
iconCreateFunction: arrowClusterIcon,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Component.addInitHook(function () {
|
||||
this.once('add', (event) => {
|
||||
if (event.target instanceof Arrows) {
|
||||
this.map = event.target._map;
|
||||
this.arrowLayer.addTo(this.map);
|
||||
}
|
||||
});
|
||||
|
||||
this.once('remove', (event) => {
|
||||
if (event.target instanceof Arrows) {
|
||||
this.arrowLayer.removeFrom(this.map);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export const Arrows = Component;
|
|
@ -1,462 +0,0 @@
|
|||
import { Map } from '$modules/Map';
|
||||
import { Poly } from '$modules/Poly';
|
||||
import { MODES } from '$constants/modes';
|
||||
import { ILatLng, Stickers } from '$modules/Stickers';
|
||||
import { Router } from '$modules/Router';
|
||||
import { DEFAULT_LOGO, ILogos, LOGOS } from '$constants/logos';
|
||||
|
||||
import { getUrlData } from '$utils/history';
|
||||
import { store } from '$redux/store';
|
||||
import {
|
||||
resetSaveDialog,
|
||||
setActiveSticker,
|
||||
setChanged,
|
||||
setDistance,
|
||||
setIsEmpty, setIsRouting,
|
||||
setMarkersShown,
|
||||
setMode,
|
||||
setRouterPoints, setStarred,
|
||||
} from '$redux/user/actions';
|
||||
import {
|
||||
mapSetAddress,
|
||||
mapSetDescription,
|
||||
mapSetLogo,
|
||||
mapSetPublic,
|
||||
mapSetTitle,
|
||||
mapSetProvider,
|
||||
} from '$redux/map/actions';
|
||||
import { DEFAULT_PROVIDER, IProvider, PROVIDERS } from '$constants/providers';
|
||||
import { STICKERS } from '$constants/stickers';
|
||||
import { IRootState } from "$redux/user";
|
||||
import { DEFAULT_USER, IUser } from "$constants/auth";
|
||||
|
||||
interface IEditor {
|
||||
map: Map;
|
||||
poly: Poly;
|
||||
stickers: Stickers;
|
||||
router: Router;
|
||||
|
||||
logo: keyof ILogos;
|
||||
owner: number;
|
||||
initialData: {
|
||||
version: number,
|
||||
title: IRootState['title'],
|
||||
owner: number,
|
||||
address: IRootState['address'],
|
||||
path: any,
|
||||
route: any,
|
||||
stickers: any,
|
||||
provider: IRootState['provider'],
|
||||
is_public: IRootState['is_public'],
|
||||
is_published: IRootState['is_published'],
|
||||
description: IRootState['description'],
|
||||
logo: IRootState['logo'],
|
||||
};
|
||||
activeSticker: IRootState['activeSticker'];
|
||||
mode: IRootState['mode'];
|
||||
provider: IProvider;
|
||||
switches: {
|
||||
[x: string]: {
|
||||
start?: () => any,
|
||||
stop?: () => any,
|
||||
toggle?: () => any,
|
||||
}
|
||||
};
|
||||
clickHandlers: {
|
||||
[x: string]: (event) => void
|
||||
};
|
||||
user: IUser;
|
||||
}
|
||||
|
||||
export class Editor {
|
||||
constructor() {
|
||||
this.logo = DEFAULT_LOGO;
|
||||
this.owner = null;
|
||||
this.map = new Map({ container: 'map' });
|
||||
this.activeSticker = {};
|
||||
this.mode = MODES.NONE;
|
||||
this.provider = PROVIDERS[DEFAULT_PROVIDER];
|
||||
|
||||
const {
|
||||
triggerOnChange, lockMapClicks, routerMoveStart, pushPolyPoints,
|
||||
map: { map }
|
||||
} = this;
|
||||
|
||||
this.poly = new Poly({
|
||||
map, routerMoveStart, lockMapClicks, setDistance: this.setDistance, triggerOnChange, editor: this,
|
||||
});
|
||||
|
||||
this.stickers = new Stickers({
|
||||
map,
|
||||
lockMapClicks,
|
||||
triggerOnChange,
|
||||
editor: this
|
||||
});
|
||||
|
||||
this.router = new Router({
|
||||
map,
|
||||
lockMapClicks,
|
||||
pushPolyPoints,
|
||||
setRouterPoints: this.setRouterPoints,
|
||||
setIsRouting: this.setIsRouting,
|
||||
});
|
||||
|
||||
this.switches = {
|
||||
[MODES.POLY]: {
|
||||
start: this.startPoly,
|
||||
stop: this.poly.stop,
|
||||
toggle: this.clearMode,
|
||||
},
|
||||
[MODES.ROUTER]: {
|
||||
toggle: this.clearMode,
|
||||
start: this.routerSetStart,
|
||||
},
|
||||
[MODES.STICKERS]: {
|
||||
toggle: this.clearSticker,
|
||||
},
|
||||
[MODES.STICKERS_SELECT]: {
|
||||
toggle: this.clearSticker,
|
||||
},
|
||||
[MODES.TRASH]: {
|
||||
toggle: this.clearMode,
|
||||
},
|
||||
[MODES.CONFIRM_CANCEL]: {
|
||||
toggle: this.cancelEditing,
|
||||
},
|
||||
[MODES.LOGO]: {
|
||||
toggle: this.clearMode,
|
||||
},
|
||||
[MODES.SAVE]: {
|
||||
toggle: this.clearMode,
|
||||
stop: this.resetSaveDialog,
|
||||
},
|
||||
[MODES.PROVIDER]: {
|
||||
toggle: this.clearMode,
|
||||
}
|
||||
};
|
||||
|
||||
this.clickHandlers = {
|
||||
[MODES.STICKERS]: this.createStickerOnClick,
|
||||
[MODES.ROUTER]: this.router.pushWaypointOnClick,
|
||||
};
|
||||
|
||||
map.addEventListener('mouseup', this.onClick);
|
||||
// map.addEventListener('touchend', this.onClick);
|
||||
map.addEventListener('dragstart', () => lockMapClicks(true));
|
||||
map.addEventListener('dragstop', () => lockMapClicks(false));
|
||||
}
|
||||
|
||||
map: IEditor['map'];
|
||||
poly: IEditor['poly'];
|
||||
stickers: IEditor['stickers'];
|
||||
router: IEditor['router'];
|
||||
|
||||
logo: IEditor['logo'] = DEFAULT_LOGO;
|
||||
owner: IEditor['owner'] = null;
|
||||
initialData: IEditor['initialData'] = {
|
||||
version: null,
|
||||
title: null,
|
||||
owner: null,
|
||||
address: null,
|
||||
path: null,
|
||||
route: null,
|
||||
stickers: null,
|
||||
provider: null,
|
||||
is_public: false,
|
||||
is_published: false,
|
||||
description: '',
|
||||
logo: null,
|
||||
};
|
||||
activeSticker: IEditor['activeSticker'];
|
||||
mode: IEditor['mode'];
|
||||
provider: IEditor['provider'];
|
||||
switches: IEditor['switches'];
|
||||
clickHandlers: IEditor['clickHandlers'];
|
||||
user: IEditor['user'] = DEFAULT_USER;
|
||||
|
||||
getState = (): IRootState => <any>store.getState().user;
|
||||
|
||||
getUser = () => this.getState().user;
|
||||
getMode = () => this.getState().mode;
|
||||
getProvider = () => this.getState().provider;
|
||||
getTitle = () => this.getState().title;
|
||||
getEditing = () => this.getState().editing;
|
||||
getChanged = () => this.getState().changed;
|
||||
getRouterPoints = () => this.getState().routerPoints;
|
||||
getDistance = () => this.getState().distance;
|
||||
getIsEmpty = () => this.getState().is_empty;
|
||||
|
||||
mapSetLogo: typeof mapSetLogo = logo => store.dispatch(mapSetLogo(logo));
|
||||
setMode: typeof setMode = value => store.dispatch(setMode(value));
|
||||
setRouterPoints: typeof setRouterPoints = value => store.dispatch(setRouterPoints(value));
|
||||
setActiveSticker: typeof setActiveSticker = value => store.dispatch(setActiveSticker(value));
|
||||
mapSetTitle: typeof mapSetTitle = value => store.dispatch(mapSetTitle(value));
|
||||
mapSetDescription: typeof mapSetDescription = value => store.dispatch(mapSetDescription(value));
|
||||
mapSetAddress: typeof mapSetAddress = value => store.dispatch(mapSetAddress(value));
|
||||
mapSetPublic: typeof mapSetPublic = value => store.dispatch(mapSetPublic(value));
|
||||
setStarred: typeof setStarred = value => store.dispatch(setStarred(value));
|
||||
setIsEmpty: typeof setIsEmpty = value => store.dispatch(setIsEmpty(value));
|
||||
setIsRouting: typeof setIsRouting = value => store.dispatch(setIsRouting(value));
|
||||
|
||||
setMarkersShown = (value: boolean): void => {
|
||||
if (this.getState().markers_shown !== value) store.dispatch(setMarkersShown(value));
|
||||
};
|
||||
|
||||
resetSaveDialog = (): void => { store.dispatch(resetSaveDialog()); };
|
||||
|
||||
setDistance = (value: number): void => {
|
||||
if (this.getDistance() !== value) store.dispatch(setDistance(value));
|
||||
};
|
||||
|
||||
setChanged = (value: boolean): void => {
|
||||
if (this.getChanged() !== value) store.dispatch(setChanged(value));
|
||||
};
|
||||
|
||||
clearMode = (): void => { this.setMode(MODES.NONE); };
|
||||
clearChanged = (): void => { store.dispatch(setChanged(false)); };
|
||||
|
||||
startPoly = (): void => {
|
||||
if (this.getRouterPoints()) this.router.clearAll();
|
||||
this.poly.continue();
|
||||
};
|
||||
|
||||
triggerOnChange = (): void => {
|
||||
if (this.isEmpty !== this.getIsEmpty()) this.setIsEmpty(this.isEmpty);
|
||||
if (this.getEditing() && !this.getChanged()) this.setChanged(true);
|
||||
};
|
||||
|
||||
createStickerOnClick = (e): void => {
|
||||
if (!e || !e.latlng || !this.activeSticker) return;
|
||||
const { latlng }: { latlng: ILatLng } = e;
|
||||
|
||||
this.stickers.createSticker({ latlng, sticker: this.activeSticker.sticker, set: this.activeSticker.set });
|
||||
this.setActiveSticker(null);
|
||||
this.setChanged(true);
|
||||
// this.setMode(MODES.STICKERS_SELECT);
|
||||
};
|
||||
|
||||
changeMode = (mode: IRootState['mode']): void => {
|
||||
if (this.mode === mode) {
|
||||
if (this.switches[mode] && this.switches[mode].toggle) {
|
||||
// if we have special function on mode when it clicked again
|
||||
this.switches[mode].toggle();
|
||||
} else {
|
||||
this.disableMode(mode);
|
||||
// this.setMode(MODES.NONE);
|
||||
this.mode = MODES.NONE;
|
||||
}
|
||||
} else {
|
||||
this.disableMode(this.mode);
|
||||
// this.setMode(mode);
|
||||
this.mode = mode;
|
||||
this.enableMode(mode);
|
||||
}
|
||||
};
|
||||
|
||||
enableMode = (mode: IRootState['mode']): void => {
|
||||
if (this.switches[mode] && this.switches[mode].start) this.switches[mode].start();
|
||||
};
|
||||
|
||||
disableMode = (mode: IRootState['mode']): void => {
|
||||
if (this.switches[mode] && this.switches[mode].stop) this.switches[mode].stop();
|
||||
};
|
||||
|
||||
onClick = (e): void => {
|
||||
if (e.originalEvent.which === 3) return; // skip right / middle click
|
||||
if (this.clickHandlers[this.mode]) this.clickHandlers[this.mode](e);
|
||||
};
|
||||
|
||||
lockMapClicks = (lock: boolean): void => {
|
||||
if (lock) {
|
||||
this.map.map.removeEventListener('mouseup', this.onClick);
|
||||
this.map.map.addEventListener('mouseup', this.unlockMapClicks);
|
||||
} else {
|
||||
this.map.map.removeEventListener('mouseup', this.unlockMapClicks);
|
||||
this.map.map.addEventListener('mouseup', this.onClick);
|
||||
}
|
||||
};
|
||||
|
||||
unlockMapClicks = (): void => {
|
||||
this.lockMapClicks(false);
|
||||
};
|
||||
|
||||
routerSetStart = (): void => {
|
||||
const { latlngs } = this.poly;
|
||||
|
||||
if (!latlngs || !latlngs.length) return;
|
||||
|
||||
this.router.startFrom(latlngs[latlngs.length - 1]);
|
||||
};
|
||||
|
||||
routerMoveStart = (): void => {
|
||||
const { _latlngs } = this.poly.poly;
|
||||
|
||||
if (_latlngs) this.router.moveStart(_latlngs[_latlngs.length - 1]);
|
||||
};
|
||||
|
||||
pushPolyPoints = (latlngs: Array<ILatLng>): void => {
|
||||
this.poly.pushPoints(latlngs);
|
||||
};
|
||||
|
||||
clearSticker = (): void => {
|
||||
if (this.activeSticker) {
|
||||
this.setActiveSticker(null);
|
||||
} else {
|
||||
this.setMode(MODES.NONE);
|
||||
}
|
||||
};
|
||||
|
||||
clearAll = (): void => {
|
||||
this.poly.clearAll();
|
||||
this.router.clearAll();
|
||||
this.stickers.clearAll();
|
||||
|
||||
this.setIsEmpty(true);
|
||||
};
|
||||
|
||||
setData = ({
|
||||
route = [],
|
||||
stickers = [],
|
||||
owner,
|
||||
title,
|
||||
address,
|
||||
provider = DEFAULT_PROVIDER,
|
||||
logo = DEFAULT_LOGO,
|
||||
is_public,
|
||||
is_published,
|
||||
description,
|
||||
}: Partial<IEditor['initialData']>): void => {
|
||||
this.mapSetTitle(title || '');
|
||||
const { id } = this.getUser();
|
||||
|
||||
if (address && id && owner && id === owner) {
|
||||
this.mapSetAddress(address);
|
||||
}
|
||||
|
||||
if (route) this.poly.setPoints(route);
|
||||
|
||||
this.stickers.clearAll();
|
||||
|
||||
if (stickers) {
|
||||
stickers.map(sticker =>
|
||||
sticker.set && STICKERS[sticker.set].url &&
|
||||
this.stickers.createSticker({
|
||||
latlng: sticker.latlng,
|
||||
angle: sticker.angle,
|
||||
sticker: sticker.sticker,
|
||||
set: sticker.set,
|
||||
text: sticker.text,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this.mapSetPublic(is_public);
|
||||
this.setStarred(is_published);
|
||||
this.mapSetDescription(description);
|
||||
|
||||
this.mapSetLogo((logo && LOGOS[DEFAULT_LOGO] && logo) || DEFAULT_LOGO);
|
||||
this.setProvider((provider && PROVIDERS[provider] && provider) || DEFAULT_PROVIDER);
|
||||
|
||||
if (owner) this.owner = owner;
|
||||
};
|
||||
|
||||
fitDrawing = (): void => {
|
||||
if (!this.poly.isEmpty) {
|
||||
const poly_bounds = this.poly.poly.getBounds();
|
||||
|
||||
if (poly_bounds && Object.values(poly_bounds).length) {
|
||||
this.map.map.fitBounds(poly_bounds);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.stickers.isEmpty) {
|
||||
const stickers_bounds = this.stickers.layer.getBounds();
|
||||
|
||||
if (stickers_bounds && Object.values(stickers_bounds).length) {
|
||||
this.map.map.fitBounds(stickers_bounds);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// no bounds to fit. better do something later
|
||||
};
|
||||
|
||||
setInitialData = (): void => {
|
||||
const { path } = getUrlData();
|
||||
const { id } = this.getUser();
|
||||
const { is_public, logo, is_published , description} = this.getState();
|
||||
const { route, stickers, provider } = this.dumpData();
|
||||
|
||||
this.initialData = {
|
||||
version: 2,
|
||||
title: this.getTitle(),
|
||||
owner: this.owner,
|
||||
address: (this.owner === id ? path : null),
|
||||
path,
|
||||
route,
|
||||
stickers,
|
||||
provider,
|
||||
is_public,
|
||||
logo,
|
||||
is_published,
|
||||
description,
|
||||
};
|
||||
};
|
||||
|
||||
startEditing = (): void => {
|
||||
const { id } = this.getUser();
|
||||
|
||||
this.setInitialData();
|
||||
this.owner = id;
|
||||
|
||||
this.poly.enableEditor();
|
||||
this.stickers.startEditing();
|
||||
};
|
||||
|
||||
stopEditing = (): void => {
|
||||
this.poly.poly.editor.disable();
|
||||
this.stickers.stopEditing();
|
||||
this.router.clearAll();
|
||||
};
|
||||
|
||||
cancelEditing = (): void => {
|
||||
if (this.hasEmptyHistory) {
|
||||
this.clearAll();
|
||||
this.startEditing();
|
||||
this.clearChanged();
|
||||
return;
|
||||
} else {
|
||||
this.setData(this.initialData);
|
||||
}
|
||||
|
||||
this.stopEditing();
|
||||
this.clearChanged();
|
||||
};
|
||||
|
||||
dumpData = () => ({
|
||||
route: this.poly.dumpData(),
|
||||
stickers: this.stickers.dumpData(),
|
||||
provider: this.getProvider(),
|
||||
});
|
||||
|
||||
setProvider: typeof mapSetProvider = provider => store.dispatch(mapSetProvider(provider));
|
||||
|
||||
get isEmpty(): boolean {
|
||||
const { route, stickers } = this.dumpData();
|
||||
|
||||
return (!route || route.length <= 1) && (!stickers || stickers.length <= 0);
|
||||
}
|
||||
|
||||
get hasEmptyHistory(): boolean {
|
||||
const { route, stickers } = this.initialData;
|
||||
|
||||
return (!route || route.length < 1) && (!stickers || stickers.length <= 0);
|
||||
};
|
||||
}
|
||||
|
||||
export const editor = new Editor();
|
||||
|
||||
// for debug purposes
|
||||
declare let window: any;
|
||||
window.editor = editor;
|
|
@ -16,7 +16,7 @@ import {
|
|||
LeafletMouseEvent,
|
||||
latLng,
|
||||
LatLngLiteral
|
||||
} from "leaflet";
|
||||
} from "leaflet";
|
||||
|
||||
import { distKm, distToSegment, getPolyLength, pointInArea } from "$utils/geom";
|
||||
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
import { divIcon, LatLngLiteral, Layer, LayerGroup, Map, marker, Marker } from "leaflet";
|
||||
import { arrowClusterIcon, createArrow } from "$utils/arrow";
|
||||
import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js';
|
||||
import { allwaysPositiveAngleDeg, angleBetweenPoints, distKm } from "$utils/geom";
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface KmMarksOptions {
|
||||
showMiddleMarkers: boolean,
|
||||
showEndMarker: boolean,
|
||||
kmMarksStep: number,
|
||||
}
|
||||
|
||||
class Component extends LayerGroup {
|
||||
constructor(latlngs?: LatLngLiteral[], options?: KmMarksOptions){
|
||||
super();
|
||||
|
||||
this.options = {
|
||||
showMiddleMarkers: true,
|
||||
showEndMarker: true,
|
||||
kmMarksStep: 10,
|
||||
...(options || {}),
|
||||
} as KmMarksOptions;
|
||||
}
|
||||
|
||||
setLatLngs = (latlngs: LatLngLiteral[]): void => {
|
||||
if (!this.map) return;
|
||||
this.marksLayer.clearLayers();
|
||||
this.endMarker.clearLayers();
|
||||
|
||||
this.distance = 0;
|
||||
|
||||
if (latlngs.length <= 1) return;
|
||||
|
||||
if (this.options.showMiddleMarkers) this.drawMiddleMarkers(latlngs);
|
||||
if (this.options.showEndMarker) this.drawEndMarker(latlngs);
|
||||
};
|
||||
|
||||
drawMiddleMarkers = (latlngs: LatLngLiteral[]) => {
|
||||
const kmMarks = {};
|
||||
let last_km_mark = 0;
|
||||
|
||||
this.distance = latlngs.reduce((dist, current, index) => {
|
||||
if (index >= latlngs.length - 1) return dist;
|
||||
|
||||
const next = latlngs[index + 1];
|
||||
const diff = distKm(current, next);
|
||||
const sum = dist + diff;
|
||||
const rounded = Math.floor(sum / this.options.kmMarksStep) * this.options.kmMarksStep;
|
||||
const count = Math.floor((rounded - last_km_mark) / this.options.kmMarksStep);
|
||||
|
||||
if (rounded > last_km_mark) {
|
||||
const angle = angleBetweenPoints(
|
||||
this.map.latLngToContainerPoint(current),
|
||||
this.map.latLngToContainerPoint(next),
|
||||
);
|
||||
|
||||
for (let i = 1; i <= count; i += 1) {
|
||||
const step = last_km_mark + (i * this.options.kmMarksStep);
|
||||
const shift = (step - dist) / diff;
|
||||
|
||||
const coords = {
|
||||
lat: current.lat - ((current.lat - next.lat) * shift),
|
||||
lng: current.lng - ((current.lng - next.lng) * shift),
|
||||
};
|
||||
|
||||
kmMarks[step] = { ...coords, angle };
|
||||
this.marksLayer.addLayer(this.createMiddleMarker(coords, angle, step));
|
||||
}
|
||||
|
||||
last_km_mark = rounded;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}, 0);
|
||||
|
||||
};
|
||||
|
||||
createMiddleMarker = (latlng: LatLngLiteral, angle: number, distance: number): Marker => marker(latlng, {
|
||||
draggable: false,
|
||||
interactive: false,
|
||||
icon: divIcon({
|
||||
html: `
|
||||
<div class="leaflet-km-dist" style="transform: translate(-50%, -50%) rotate(${allwaysPositiveAngleDeg(angle)}deg);">
|
||||
${distance}
|
||||
</div>
|
||||
`,
|
||||
className: 'leaflet-km-marker',
|
||||
iconSize: [11, 11],
|
||||
iconAnchor: [6, 6]
|
||||
})
|
||||
});
|
||||
|
||||
createEndMarker = (latlng: LatLngLiteral, angle: number, distance: number): Marker => marker(latlng, {
|
||||
draggable: false,
|
||||
interactive: false,
|
||||
icon: divIcon({
|
||||
html: `
|
||||
<div class="leaflet-km-dist">
|
||||
${parseFloat(distance.toFixed(1))}
|
||||
</div>
|
||||
`,
|
||||
className: classNames('leaflet-km-marker end-marker', { right: (angle > -90 && angle < 90) }),
|
||||
iconSize: [11, 11],
|
||||
iconAnchor: [6, 6]
|
||||
}),
|
||||
zIndexOffset: -100,
|
||||
});
|
||||
|
||||
drawEndMarker = (latlngs: LatLngLiteral[]): void => {
|
||||
this.endMarker.clearLayers();
|
||||
|
||||
const current = latlngs[latlngs.length - 2];
|
||||
const next = latlngs[latlngs.length - 1
|
||||
];
|
||||
|
||||
const angle = angleBetweenPoints(
|
||||
this.map.latLngToContainerPoint(current),
|
||||
this.map.latLngToContainerPoint(next),
|
||||
);
|
||||
|
||||
this.endMarker.addLayer(this.createEndMarker(next, angle, this.distance));
|
||||
};
|
||||
|
||||
options: KmMarksOptions;
|
||||
map: Map;
|
||||
marksLayer: MarkerClusterGroup = new MarkerClusterGroup({
|
||||
spiderfyOnMaxZoom: false,
|
||||
showCoverageOnHover: false,
|
||||
zoomToBoundsOnClick: false,
|
||||
animate: false,
|
||||
maxClusterRadius: 120,
|
||||
iconCreateFunction: arrowClusterIcon,
|
||||
});
|
||||
endMarker: LayerGroup = new LayerGroup();
|
||||
distance: number = 0;
|
||||
}
|
||||
|
||||
|
||||
Component.addInitHook(function () {
|
||||
this.once('add', (event) => {
|
||||
if (event.target instanceof KmMarks) {
|
||||
this.map = event.target._map;
|
||||
this.marksLayer.addTo(this.map);
|
||||
this.endMarker.addTo(this.map);
|
||||
}
|
||||
});
|
||||
|
||||
this.once('remove', (event) => {
|
||||
if (event.target instanceof KmMarks) {
|
||||
this.marksLayer.removeFrom(this.map);
|
||||
this.endMarker.removeFrom(this.map);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
export const KmMarks = Component;
|
|
@ -1,36 +0,0 @@
|
|||
import {
|
||||
Map as MapInterface,
|
||||
map,
|
||||
tileLayer,
|
||||
TileLayer,
|
||||
} from 'leaflet';
|
||||
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
import { PROVIDER } from '$config/frontend';
|
||||
import { DEFAULT_PROVIDER, PROVIDERS } from '$constants/providers';
|
||||
|
||||
interface Props {
|
||||
container: string
|
||||
}
|
||||
|
||||
export class Map {
|
||||
constructor({ container }: Props) {
|
||||
this.map = map(container).setView([55.0153275, 82.9071235], 13);
|
||||
// todo: change coords?
|
||||
|
||||
this.tileLayer.addTo(this.map);
|
||||
}
|
||||
|
||||
map: MapInterface;
|
||||
tileLayer: TileLayer = tileLayer(PROVIDER.url, {
|
||||
attribution: 'Независимое Велосообщество',
|
||||
maxNativeZoom: 18,
|
||||
maxZoom: 18,
|
||||
});
|
||||
|
||||
setProvider = (provider: string): void => {
|
||||
const { url } = (provider && PROVIDERS[provider] && PROVIDERS[provider]) || PROVIDERS[DEFAULT_PROVIDER];
|
||||
|
||||
this.tileLayer.setUrl(url);
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
import { Map, LatLng } from 'leaflet';
|
||||
import { simplify } from '$utils/simplify';
|
||||
import { editor, Editor } from "$modules/Editor";
|
||||
import { ILatLng } from "$modules/Stickers";
|
||||
import { InteractivePoly } from "$modules/InteractivePoly";
|
||||
import { Arrows } from "$modules/Arrows";
|
||||
import { KmMarks } from "$modules/KmMarks";
|
||||
import { isMobile } from "$utils/window";
|
||||
|
||||
interface Props {
|
||||
map: Map;
|
||||
editor: Editor;
|
||||
routerMoveStart: typeof editor.routerMoveStart,
|
||||
lockMapClicks: typeof editor.lockMapClicks,
|
||||
setDistance: typeof editor.setDistance,
|
||||
triggerOnChange: typeof editor.triggerOnChange,
|
||||
}
|
||||
|
||||
export class Poly {
|
||||
constructor({
|
||||
map, routerMoveStart, lockMapClicks, setDistance, triggerOnChange, editor,
|
||||
}: Props) {
|
||||
this.poly = new InteractivePoly([ ], {
|
||||
color: 'url(#activePathGradient)',
|
||||
weight: 6,
|
||||
maxMarkers: isMobile() ? 20 : 100,
|
||||
smoothFactor: 3,
|
||||
})
|
||||
.on('distancechange', this.onDistanceUpdate)
|
||||
.on('allvertexhide', this.onVertexHide)
|
||||
.on('allvertexshow', this.onVertexShow)
|
||||
.on('latlngschange', this.updateMarks)
|
||||
|
||||
this.poly.addTo(map);
|
||||
this.editor = editor;
|
||||
|
||||
this.map = map;
|
||||
|
||||
this.routerMoveStart = routerMoveStart;
|
||||
this.setDistance = setDistance;
|
||||
this.triggerOnChange = triggerOnChange;
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
|
||||
this.arrows = new Arrows({}).addTo(map);
|
||||
this.kmMarks = new KmMarks().addTo(map);
|
||||
}
|
||||
|
||||
onDistanceUpdate = (event) => {
|
||||
const { distance } = event as { distance: number };
|
||||
this.setDistance(parseFloat(distance.toFixed(2)));
|
||||
};
|
||||
|
||||
onVertexHide = (): void => this.editor.setMarkersShown(false);
|
||||
onVertexShow = (): void => this.editor.setMarkersShown(true);
|
||||
|
||||
updateMarks = event => {
|
||||
// this.editor.setChanged(true);
|
||||
this.editor.triggerOnChange();
|
||||
|
||||
const { latlngs } = event;
|
||||
this.arrows.setLatLngs(latlngs);
|
||||
this.kmMarks.setLatLngs(latlngs);
|
||||
};
|
||||
|
||||
continue = (): void => {
|
||||
this.poly.editor.continue();
|
||||
};
|
||||
|
||||
stop = (): void => {
|
||||
this.poly.stopDrawing();
|
||||
};
|
||||
|
||||
enableEditor = (): void => {
|
||||
this.poly.editor.enable();
|
||||
};
|
||||
|
||||
setPoints = (latlngs: Array<ILatLng>): void => {
|
||||
if (!latlngs || latlngs.length <= 1) return;
|
||||
this.poly.setPoints(latlngs);
|
||||
};
|
||||
|
||||
pushPoints = (latlngs: Array<ILatLng>): void => {
|
||||
const { map } = this;
|
||||
const simplified = simplify({ map, latlngs });
|
||||
const summary = [
|
||||
...this.poly.getLatLngs(),
|
||||
...simplified,
|
||||
];
|
||||
|
||||
this.poly.setPoints(summary);
|
||||
};
|
||||
|
||||
clearAll = (): void => {
|
||||
this.poly.setPoints([]);
|
||||
};
|
||||
|
||||
dumpData = (): Array<LatLng> => this.latlngs;
|
||||
|
||||
get latlngs(): Array<LatLng> {
|
||||
return (
|
||||
this.poly && this.poly.getLatLngs().length
|
||||
&& this.poly.getLatLngs().map(el => ({ ...el }))) || [];
|
||||
}
|
||||
|
||||
get isEmpty(): boolean {
|
||||
return (!this.latlngs || Object.values(this.latlngs).length <= 0);
|
||||
}
|
||||
|
||||
arrows;
|
||||
poly;
|
||||
kmMarks;
|
||||
|
||||
editor: Props['editor'];
|
||||
map: Props['map'];
|
||||
routerMoveStart: Props['routerMoveStart'];
|
||||
setDistance: Props['setDistance'];
|
||||
triggerOnChange: Props['triggerOnChange'];
|
||||
lockMapClicks: Props['lockMapClicks'];
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
import { Map, Marker } from 'leaflet';
|
||||
import * as Routing from 'leaflet-routing-machine/src/index';
|
||||
import { CLIENT } from '$config/frontend';
|
||||
import { DomMarker } from '$utils/DomMarker';
|
||||
import { editor } from "$modules/Editor";
|
||||
|
||||
interface ILatLng {
|
||||
lat: number, lng: number
|
||||
}
|
||||
|
||||
interface IWaypoint {
|
||||
latLng: ILatLng
|
||||
}
|
||||
|
||||
interface Props {
|
||||
setIsRouting: typeof editor.setIsRouting,
|
||||
map: Map,
|
||||
setRouterPoints: typeof editor.setRouterPoints,
|
||||
pushPolyPoints: typeof editor.pushPolyPoints,
|
||||
lockMapClicks: typeof editor.lockMapClicks;
|
||||
}
|
||||
|
||||
export class Router {
|
||||
constructor({
|
||||
map, lockMapClicks, setRouterPoints, pushPolyPoints, setIsRouting,
|
||||
}: Props) {
|
||||
this.waypoints = [];
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
this.setRouterPoints = setRouterPoints;
|
||||
this.pushPolyPoints = pushPolyPoints;
|
||||
this.setIsRouting = setIsRouting;
|
||||
|
||||
const routeLine = r => Routing.line(r, {
|
||||
styles: [
|
||||
{ color: 'white', opacity: 0.8, weight: 6 },
|
||||
{ color: '#4597d0', opacity: 1, weight: 4, dashArray: '15,10' }
|
||||
],
|
||||
addWaypoints: true,
|
||||
}).on('linetouched', this.lockPropagations);
|
||||
|
||||
this.router = Routing.control({
|
||||
serviceUrl: CLIENT.OSRM_URL,
|
||||
profile: CLIENT.OSRM_PROFILE,
|
||||
fitSelectedRoutes: false,
|
||||
showAlternatives: false,
|
||||
routeLine,
|
||||
altLineOptions: {
|
||||
styles: [{ color: '#4597d0', opacity: 1, weight: 3 }]
|
||||
},
|
||||
show: false,
|
||||
plan: Routing.plan([], {
|
||||
createMarker: (i, wp) => new Marker(wp.latLng, {
|
||||
draggable: true,
|
||||
icon: this.createWaypointMarker(),
|
||||
}),
|
||||
routeWhileDragging: false,
|
||||
}),
|
||||
routeWhileDragging: false,
|
||||
routingOptions: {
|
||||
geometryOnly: false,
|
||||
},
|
||||
useHints: false,
|
||||
})
|
||||
.on('routingstart', this.showSpinner)
|
||||
.on('routesfound routingerror routeselected routingzoomend', this.hideSpinner)
|
||||
.on('waypointschanged', this.updateWaypointsCount);
|
||||
|
||||
this.router.addTo(map);
|
||||
}
|
||||
|
||||
showSpinner = () => {
|
||||
this.setIsRouting(true);
|
||||
};
|
||||
|
||||
hideSpinner = () => {
|
||||
this.setIsRouting(false);
|
||||
};
|
||||
|
||||
pushWaypointOnClick = ({ latlng: { lat, lng } }: { latlng: ILatLng }): void => {
|
||||
const waypoints = this.router.getWaypoints().filter(({ latLng }) => !!latLng);
|
||||
this.router.setWaypoints([...waypoints, { lat, lng }]);
|
||||
};
|
||||
|
||||
createWaypointMarker = (): DomMarker => {
|
||||
const element = document.createElement('div');
|
||||
|
||||
element.addEventListener('mousedown', this.lockPropagations);
|
||||
element.addEventListener('mouseup', this.unlockPropagations);
|
||||
|
||||
return new DomMarker({
|
||||
element,
|
||||
className: 'router-waypoint',
|
||||
});
|
||||
};
|
||||
|
||||
lockPropagations = (): void => {
|
||||
window.addEventListener('mouseup', this.unlockPropagations);
|
||||
this.lockMapClicks(true);
|
||||
};
|
||||
|
||||
unlockPropagations = (e): void => {
|
||||
if (e && e.preventPropagations) {
|
||||
e.preventDefault();
|
||||
e.preventPropagations();
|
||||
}
|
||||
|
||||
window.removeEventListener('mouseup', this.unlockPropagations);
|
||||
setTimeout(() => this.lockMapClicks(false), 0);
|
||||
};
|
||||
|
||||
startFrom = (latlngs: ILatLng): void => {
|
||||
const waypoints = this.router.getWaypoints();
|
||||
|
||||
if (waypoints && waypoints.length) {
|
||||
waypoints[0] = { ...latlngs };
|
||||
this.router.setWaypoints(waypoints);
|
||||
return;
|
||||
}
|
||||
|
||||
this.router.setWaypoints([{ ...latlngs }]);
|
||||
};
|
||||
|
||||
moveStart = (latlng: ILatLng): void => {
|
||||
const waypoints = this.router.getWaypoints();
|
||||
const { latLng }: { latLng: ILatLng } = (waypoints[0] || {});
|
||||
|
||||
if (!latLng || !latlng) return;
|
||||
|
||||
if (
|
||||
latlng.lat.toFixed(5) === latLng.lat.toFixed(5) &&
|
||||
latlng.lng.toFixed(5) === latLng.lng.toFixed(5)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
waypoints[0] = { ...latlng };
|
||||
|
||||
this.router.setWaypoints(waypoints);
|
||||
};
|
||||
|
||||
updateWaypointsCount = (): void => {
|
||||
const waypoints = this.router.getWaypoints().filter(({ latLng }) => !!latLng);
|
||||
this.setRouterPoints(waypoints.length);
|
||||
};
|
||||
|
||||
cancelDrawing = (): void => {
|
||||
this.router.setWaypoints([]);
|
||||
};
|
||||
|
||||
submitDrawing = (): void => {
|
||||
const [route] = this.router._routes;
|
||||
if (!route) return;
|
||||
|
||||
const { coordinates } = route;
|
||||
this.pushPolyPoints(coordinates);
|
||||
|
||||
this.router.setWaypoints([]);
|
||||
|
||||
// UNCOMMENT THIS TO CONTINUE DRAWING
|
||||
// const waypoints = this.router.getWaypoints().filter(({ latLng }) => !!latLng);
|
||||
// this.router.setWaypoints(waypoints[waypoints.length - 1]);
|
||||
};
|
||||
|
||||
clearAll = (): void => {
|
||||
this.router.setWaypoints([]);
|
||||
};
|
||||
|
||||
waypoints: Array<IWaypoint> = [];
|
||||
setIsRouting: Props['setIsRouting'];
|
||||
lockMapClicks: Props['lockMapClicks'];
|
||||
setRouterPoints: Props['setRouterPoints'];
|
||||
pushPolyPoints: Props['pushPolyPoints'];
|
||||
router: Routing;
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
import { Map, Marker, marker } from 'leaflet';
|
||||
import * as React from 'react';
|
||||
import { DomMarker } from '$utils/DomMarker';
|
||||
|
||||
import { STICKERS } from '$constants/stickers';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { StickerDesc } from '$components/StickerDesc';
|
||||
import classnames from 'classnames';
|
||||
import { getLabelDirection } from '$utils/geom';
|
||||
import { ILatLng } from "$modules/Stickers";
|
||||
import { IRootState } from "$redux/user";
|
||||
import { Editor, editor } from "$modules/Editor";
|
||||
|
||||
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 }
|
||||
);
|
||||
|
||||
|
||||
export interface IStickerDump {
|
||||
latlng: ILatLng,
|
||||
set: IRootState['activeSticker']['set'],
|
||||
sticker: IRootState['activeSticker']['sticker'],
|
||||
angle?: number,
|
||||
text?: string,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
latlng: ILatLng;
|
||||
map: Map;
|
||||
sticker: IRootState['activeSticker']['sticker'];
|
||||
set: IRootState['activeSticker']['set'];
|
||||
angle?: number;
|
||||
text?: string;
|
||||
editor: Editor,
|
||||
|
||||
deleteSticker: (sticker: this) => void;
|
||||
|
||||
triggerOnChange: typeof editor.triggerOnChange;
|
||||
lockMapClicks: typeof editor.lockMapClicks;
|
||||
}
|
||||
|
||||
export class Sticker {
|
||||
constructor({
|
||||
latlng, deleteSticker, map, lockMapClicks, sticker, set, triggerOnChange, angle = 2.2, text = '', editor,
|
||||
}: Props) {
|
||||
this.text = text;
|
||||
this.latlng = latlng;
|
||||
this.angle = parseFloat(((angle && (angle % Math.PI)) || 2.2).toFixed(2));
|
||||
this.map = map;
|
||||
this.sticker = sticker;
|
||||
this.set = set;
|
||||
this.triggerOnChange = triggerOnChange;
|
||||
this.direction = getLabelDirection(this.angle);
|
||||
this.deleteSticker = deleteSticker;
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
this.editor = editor;
|
||||
this.element = document.createElement('div');
|
||||
|
||||
ReactDOM.render(
|
||||
<React.Fragment>
|
||||
<div
|
||||
className="sticker-arrow"
|
||||
ref={el => { this.stickerArrow = el; }}
|
||||
/>
|
||||
<div
|
||||
className={classnames(`sticker-label ${this.direction}`, {})}
|
||||
ref={el => { this.stickerImage = el; }}
|
||||
>
|
||||
<StickerDesc value={this.text} onChange={this.setText} />
|
||||
<div
|
||||
className="sticker-image"
|
||||
style={{
|
||||
backgroundImage: `url('${STICKERS[set].url}`,
|
||||
backgroundPosition: `${-STICKERS[set].layers[sticker].off * 72} 50%`,
|
||||
}}
|
||||
onMouseDown={this.onDragStart}
|
||||
onMouseUp={this.onDragStop}
|
||||
onTouchStart={this.onDragStart}
|
||||
onTouchEnd={this.onDragStop}
|
||||
/>
|
||||
<div
|
||||
className="sticker-delete"
|
||||
onMouseDown={this.onDelete}
|
||||
onTouchStart={this.onDelete}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>,
|
||||
this.element
|
||||
);
|
||||
|
||||
const mark = new DomMarker({
|
||||
element: this.element,
|
||||
className: 'sticker-container',
|
||||
});
|
||||
|
||||
this.marker = marker(latlng, { icon: mark, draggable: true });
|
||||
|
||||
this.marker.on('add', this.updateModeOnAdd);
|
||||
|
||||
this.element.addEventListener('mouseup', this.onDragStop);
|
||||
this.element.addEventListener('mouseup', this.preventPropagations);
|
||||
|
||||
this.element.addEventListener('touchend', this.onDragStop);
|
||||
this.element.addEventListener('touchend', this.preventPropagations);
|
||||
|
||||
this.marker.on('dragend', this.triggerOnChange);
|
||||
|
||||
this.setAngle(this.angle);
|
||||
}
|
||||
|
||||
updateModeOnAdd = () => {
|
||||
if (this.editor.getEditing()) {
|
||||
this.startEditing();
|
||||
} else {
|
||||
this.stopEditing();
|
||||
}
|
||||
};
|
||||
|
||||
setText = (text: Props['text']): void => {
|
||||
this.text = text;
|
||||
};
|
||||
|
||||
onDelete = (): void => {
|
||||
if (!this.isDragging) this.deleteSticker(this);
|
||||
};
|
||||
|
||||
onDragStart = (e): void => {
|
||||
this.preventPropagations(e);
|
||||
this.marker.dragging.disable();
|
||||
|
||||
this.isDragging = true;
|
||||
|
||||
this.lockMapClicks(true);
|
||||
|
||||
window.addEventListener('mousemove', this.onDrag);
|
||||
window.addEventListener('touchmove', this.onDrag);
|
||||
|
||||
window.addEventListener('mouseup', this.onDragStop);
|
||||
window.addEventListener('touchend', this.onDragStop);
|
||||
};
|
||||
|
||||
preventPropagations = (e): void => {
|
||||
if (!e || !e.stopPropagation) return;
|
||||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
onDragStop = (e): void => {
|
||||
this.preventPropagations(e);
|
||||
this.marker.dragging.enable();
|
||||
|
||||
this.triggerOnChange();
|
||||
this.isDragging = false;
|
||||
|
||||
window.removeEventListener('mousemove', this.onDrag);
|
||||
window.removeEventListener('touchmove', this.onDrag);
|
||||
|
||||
window.removeEventListener('mouseup', this.onDragStop);
|
||||
window.removeEventListener('touchend', this.onDragStop);
|
||||
|
||||
this.lockMapClicks(false);
|
||||
};
|
||||
|
||||
onDrag = (e: DragEvent): void => {
|
||||
this.preventPropagations(e);
|
||||
this.estimateAngle(e);
|
||||
};
|
||||
|
||||
estimateAngle = (e): void => {
|
||||
const { x, y } = this.element.getBoundingClientRect() as DOMRect;
|
||||
const { pageX, pageY } = getX(e);
|
||||
|
||||
this.angle = parseFloat(Math.atan2((y - pageY), (x - pageX)).toFixed(2));
|
||||
|
||||
this.setAngle(this.angle);
|
||||
};
|
||||
|
||||
setAngle = (angle: Props['angle']): void => {
|
||||
if (!this.stickerImage) return;
|
||||
|
||||
const direction = getLabelDirection(angle);
|
||||
|
||||
if (direction !== this.direction) {
|
||||
this.direction = direction;
|
||||
this.stickerImage.className = `sticker-label ${direction}`;
|
||||
}
|
||||
|
||||
const rad = 56;
|
||||
|
||||
const x = ((Math.cos(angle + Math.PI) * rad) - 30);
|
||||
const y = ((Math.sin(angle + Math.PI) * rad) - 30);
|
||||
|
||||
this.stickerImage.style.left = String(6 + x);
|
||||
this.stickerImage.style.top = String(6 + y);
|
||||
|
||||
this.stickerArrow.style.transform = `rotate(${angle + Math.PI}rad)`;
|
||||
};
|
||||
|
||||
dumpData = (): IStickerDump => ({
|
||||
angle: this.angle,
|
||||
latlng: { ...this.marker.getLatLng() },
|
||||
sticker: this.sticker,
|
||||
set: this.set,
|
||||
text: this.text,
|
||||
});
|
||||
|
||||
stopEditing = (): void => {
|
||||
this.element.className = 'sticker-container inactive';
|
||||
};
|
||||
|
||||
startEditing = (): void => {
|
||||
this.element.className = 'sticker-container';
|
||||
};
|
||||
|
||||
element: HTMLDivElement = document.createElement('div');
|
||||
stickerImage: HTMLDivElement;
|
||||
stickerArrow: HTMLDivElement;
|
||||
marker: Marker;
|
||||
isDragging: boolean = false;
|
||||
direction: string;
|
||||
editor: Editor;
|
||||
|
||||
text: Props['text'];
|
||||
latlng: Props['latlng'];
|
||||
angle: Props['angle'];
|
||||
map: Props['map'];
|
||||
sticker: Props['sticker'];
|
||||
set: Props['set'];
|
||||
triggerOnChange: Props['triggerOnChange'];
|
||||
|
||||
deleteSticker: Props['deleteSticker'];
|
||||
lockMapClicks: Props['lockMapClicks'];
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
import {FeatureGroup, LayerGroup, layerGroup, Map} from 'leaflet';
|
||||
import { IStickerDump, Sticker } from '$modules/Sticker';
|
||||
import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js';
|
||||
import { clusterIcon } from '$utils/clusterIcon';
|
||||
import { editor, Editor } from "$modules/Editor";
|
||||
import { STICKERS } from "$constants/stickers";
|
||||
|
||||
export interface ILatLng {
|
||||
lat: number,
|
||||
lng: number,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
editor: Editor;
|
||||
map: Map;
|
||||
|
||||
triggerOnChange: typeof editor.triggerOnChange;
|
||||
lockMapClicks: typeof editor.lockMapClicks;
|
||||
}
|
||||
|
||||
export class Stickers {
|
||||
constructor({ map, lockMapClicks, triggerOnChange, editor }: Props) {
|
||||
this.map = map;
|
||||
this.triggerOnChange = triggerOnChange;
|
||||
this.editor = editor;
|
||||
|
||||
// this.clusterLayer.addTo(map);
|
||||
// this.clusterLayer.on('animationend', this.onSpiderify);
|
||||
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
this.stickers = [];
|
||||
|
||||
this.layer.addTo(this.map);
|
||||
}
|
||||
|
||||
createSticker = ({
|
||||
latlng, sticker, angle = 2.2, text = '', set
|
||||
}: IStickerDump): void => {
|
||||
|
||||
if (!STICKERS[set] || !STICKERS[set].layers || !STICKERS[set].layers[sticker]) return;
|
||||
|
||||
const marker = new Sticker({
|
||||
latlng,
|
||||
angle,
|
||||
deleteSticker: this.deleteStickerByReference,
|
||||
map: this.map,
|
||||
lockMapClicks: this.lockMapClicks,
|
||||
sticker,
|
||||
set,
|
||||
triggerOnChange: this.triggerOnChange,
|
||||
text,
|
||||
editor: this.editor,
|
||||
});
|
||||
|
||||
this.stickers.push(marker);
|
||||
|
||||
marker.marker.addTo(this.layer);
|
||||
|
||||
this.triggerOnChange();
|
||||
};
|
||||
|
||||
deleteStickerByReference = (ref: Sticker): void => {
|
||||
const index = this.stickers.indexOf(ref);
|
||||
|
||||
if (index < 0) return;
|
||||
|
||||
// this.clusterLayer.removeLayer(ref.marker);
|
||||
this.layer.removeLayer(ref.marker);
|
||||
this.stickers.splice(index, 1);
|
||||
|
||||
this.triggerOnChange();
|
||||
};
|
||||
|
||||
clearAll = (): void => {
|
||||
const target = [...this.stickers];
|
||||
target.map(sticker => {
|
||||
this.deleteStickerByReference(sticker);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
dumpData = (): Array<IStickerDump> => this.stickers.map(sticker => sticker.dumpData());
|
||||
|
||||
startEditing = (): void => {
|
||||
this.stickers.map(sticker => sticker.startEditing());
|
||||
};
|
||||
|
||||
stopEditing = (): void => {
|
||||
this.stickers.map(sticker => sticker.stopEditing());
|
||||
};
|
||||
|
||||
get isEmpty(): boolean {
|
||||
return !this.stickers || this.stickers.length === 0
|
||||
};
|
||||
// clusterLayer: LayerGroup = new LayerGroup();
|
||||
|
||||
// uncomment to enable clustering
|
||||
|
||||
// clusterLayer: MarkerClusterGroup = new MarkerClusterGroup({
|
||||
// spiderfyOnMaxZoom: false,
|
||||
// showCoverageOnHover: false,
|
||||
// zoomToBoundsOnClick: true,
|
||||
// animate: false,
|
||||
// maxClusterRadius: 8,
|
||||
// // disableClusteringAtZoom: 13,
|
||||
// iconCreateFunction: clusterIcon,
|
||||
// });
|
||||
|
||||
editor: Props['editor'];
|
||||
map: Props['map'];
|
||||
|
||||
stickers: Array<Sticker> = [];
|
||||
layer: FeatureGroup = new FeatureGroup();
|
||||
|
||||
triggerOnChange: Props['triggerOnChange'];
|
||||
lockMapClicks: Props['lockMapClicks'];
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue