From 69d1d749cf8e3585c4cd7e825137d41fee58beeb Mon Sep 17 00:00:00 2001 From: Fedor Katurov Date: Thu, 16 Jan 2020 11:49:24 +0700 Subject: [PATCH] refactored rerendering speed --- package-lock.json | 38 +- package.json | 11 +- src/_modules/Editor.ts | 462 ------------- src/_modules/InteractivePoly.ts | 606 ------------------ src/_modules/KmMarks.ts | 156 ----- src/_modules/Map.ts | 36 -- src/_modules/Poly.ts | 119 ---- src/_modules/Router.ts | 174 ----- src/_modules/Sticker.tsx | 236 ------- src/_modules/Stickers.ts | 117 ---- src/components/dialogs/MapListDialog.tsx | 11 +- src/components/dialogs/RouterDialog.tsx | 5 +- src/components/maps/RouteRowDrop.tsx | 36 +- src/components/panels/DistanceBar.tsx | 48 +- src/components/panels/EditorPanel.tsx | 18 +- src/components/panels/Icon.tsx | 7 +- src/components/panels/TopLeftPanel.tsx | 6 +- src/components/panels/TopRightPanel.tsx | 17 +- src/components/panels/UserPanel.tsx | 21 +- src/components/user/UserButton.tsx | 17 +- src/containers/App.tsx | 10 +- src/containers/LeftDialog.tsx | 16 +- src/containers/map/Route/index.tsx | 2 +- src/containers/map/Router/index.tsx | 4 +- src/containers/map/Sticker/index.tsx | 2 +- src/redux/editor/sagas.ts | 4 +- src/utils/arrow.ts | 5 - src/{_modules => utils/map}/Arrows.ts | 0 src/utils/{ => map}/DomMarker.js | 2 +- .../{polyline.ts => map/InteractivePoly.ts} | 1 - src/utils/{osrm.ts => map/OsrmRouter.ts} | 2 +- src/utils/{ => map}/clusterIcon.ts | 0 32 files changed, 144 insertions(+), 2045 deletions(-) delete mode 100644 src/_modules/Editor.ts delete mode 100644 src/_modules/InteractivePoly.ts delete mode 100644 src/_modules/KmMarks.ts delete mode 100644 src/_modules/Map.ts delete mode 100644 src/_modules/Poly.ts delete mode 100644 src/_modules/Router.ts delete mode 100644 src/_modules/Sticker.tsx delete mode 100644 src/_modules/Stickers.ts rename src/{_modules => utils/map}/Arrows.ts (100%) rename src/utils/{ => map}/DomMarker.js (94%) rename src/utils/{polyline.ts => map/InteractivePoly.ts} (99%) rename src/utils/{osrm.ts => map/OsrmRouter.ts} (96%) rename src/utils/{ => map}/clusterIcon.ts (100%) diff --git a/package-lock.json b/package-lock.json index 67bd187..23cd49a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -778,17 +778,20 @@ "@types/classnames": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.7.tgz", - "integrity": "sha512-rzOhiQ55WzAiFgXRtitP/ZUT8iVNyllEpylJ5zHzR4vArUvMB39GTk+Zon/uAM0JxEFAWnwsxC2gH8s+tZ3Myg==" + "integrity": "sha512-rzOhiQ55WzAiFgXRtitP/ZUT8iVNyllEpylJ5zHzR4vArUvMB39GTk+Zon/uAM0JxEFAWnwsxC2gH8s+tZ3Myg==", + "dev": true }, "@types/geojson": { "version": "7946.0.6", "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.6.tgz", - "integrity": "sha512-f6qai3iR62QuMPPdgyH+LyiXTL2n9Rf62UniJjV7KHrbiwzLTZUKsdq0mFSTxAHbO7JvwxwC4tH0m1UnweuLrA==" + "integrity": "sha512-f6qai3iR62QuMPPdgyH+LyiXTL2n9Rf62UniJjV7KHrbiwzLTZUKsdq0mFSTxAHbO7JvwxwC4tH0m1UnweuLrA==", + "dev": true }, "@types/leaflet": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.4.3.tgz", "integrity": "sha512-jFRBSsPHi1EwQSwrN0cOJLdPhwOZsRl4IMxvm/2ShLh0YM5GfCtQXCzsrv8RE7DWL+AykXdYSAd9bFLWbZT4CQ==", + "dev": true, "requires": { "@types/geojson": "7946.0.6" } @@ -796,22 +799,34 @@ "@types/node": { "version": "11.9.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.0.tgz", - "integrity": "sha512-ry4DOrC+xenhQbzk1iIPzCZGhhPGEFv7ia7Iu6XXSLVluiJIe9FfG7Iu3mObH9mpxEXCWLCMU4JWbCCR9Oy1Zg==" + "integrity": "sha512-ry4DOrC+xenhQbzk1iIPzCZGhhPGEFv7ia7Iu6XXSLVluiJIe9FfG7Iu3mObH9mpxEXCWLCMU4JWbCCR9Oy1Zg==", + "dev": true }, "@types/prop-types": { "version": "15.5.8", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.8.tgz", - "integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==" + "integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==", + "dev": true }, "@types/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.1.tgz", "integrity": "sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA==" }, + "@types/ramda": { + "version": "0.26.39", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.26.39.tgz", + "integrity": "sha512-3bu32X02VpjJhsYPUWkdOQGoBXjb/UveZgGg4IYMm+SPAXio96BOYrRhVELfM4AoP00sxoi/f2tqrXdwtR4jjg==", + "dev": true, + "requires": { + "ts-toolbelt": "4.14.6" + } + }, "@types/react": { "version": "16.8.1", "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.1.tgz", "integrity": "sha512-tD1ETKJcuhANOejRc/p7OgQ16DKnbGi0M3LccelKlPnUCDp2a5koVxZFoRN9HN+A+m84HB5VGN7I+r3nNhS3PA==", + "dev": true, "requires": { "@types/prop-types": "15.5.8", "csstype": "2.6.2" @@ -4464,7 +4479,8 @@ "csstype": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.2.tgz", - "integrity": "sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==" + "integrity": "sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==", + "dev": true }, "currently-unhandled": { "version": "0.4.1", @@ -13015,6 +13031,12 @@ "yn": "3.0.0" } }, + "ts-toolbelt": { + "version": "4.14.6", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-4.14.6.tgz", + "integrity": "sha512-SONcnRd93+LuYGfn/CZg5A5qhCODohZslAVZKHHu5bnwUxoXLqd2k2VIdwRUXYfKnY+UCeNbI2pTPz+Dno6Mpg==", + "dev": true + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", @@ -13085,9 +13107,9 @@ "integrity": "sha512-NLpRc/FY+jPfWL0aUXQzjxPyF0Xug2om6akaoRLQ18KGwP2yYNBJu9vkv2q1q+Cx/+edy2Qf6O8xXnYY/xwz1A==" }, "typescript": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz", - "integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", + "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==", "dev": true }, "uglifyjs-webpack-plugin": { diff --git a/package.json b/package.json index 0bd8aea..5c75fc7 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,11 @@ "devDependencies": { "@babel/cli": "^7.0.0-rc.1", "@babel/preset-env": "^7.0.0-rc.1", + "@types/ramda": "^0.26.39", + "@types/classnames": "^2.2.7", + "@types/leaflet": "^1.4.3", + "@types/node": "^11.9.0", + "@types/react": "16.8.1", "awesome-typescript-loader": "^5.2.1", "babel-core": "^6.26.0", "babel-eslint": "^8.2.3", @@ -43,7 +48,7 @@ "style-loader": "^0.21.0", "sw-precache-webpack-plugin": "^0.11.5", "ts-node": "^8.0.1", - "typescript": "^3.2.4", + "typescript": "^3.7.4", "uglifyjs-webpack-plugin": "^1.3.0", "webpack": "^4.6.0", "webpack-cli": "^3.2.3", @@ -52,10 +57,6 @@ "webpack-pwa-manifest": "^4.0.0" }, "dependencies": { - "@types/classnames": "^2.2.7", - "@types/leaflet": "^1.4.3", - "@types/node": "^11.9.0", - "@types/react": "16.8.1", "axios": "^0.18.0", "babel-runtime": "^6.26.0", "body-parser": "^1.18.3", diff --git a/src/_modules/Editor.ts b/src/_modules/Editor.ts deleted file mode 100644 index 79bd824..0000000 --- a/src/_modules/Editor.ts +++ /dev/null @@ -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 => 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): 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): 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; diff --git a/src/_modules/InteractivePoly.ts b/src/_modules/InteractivePoly.ts deleted file mode 100644 index 2d021ab..0000000 --- a/src/_modules/InteractivePoly.ts +++ /dev/null @@ -1,606 +0,0 @@ -/* - done IMPORTANT: select closest point on drag instead of first - done add touch hint poly - done approx radius for dragFindNearest -*/ - -import { - LatLngExpression, - Marker, - Polyline, - PolylineOptions, - marker, - divIcon, - LayerGroup, - LatLng, - LeafletMouseEvent, - latLng, - LatLngLiteral -} from "leaflet"; - -import { distKmHaversine, distToSegment, getPolyLength, pointInArea } from "~/utils/geom"; - -interface InteractivePolylineOptions extends PolylineOptions { - maxMarkers?: number; - constraintsStyle?: PolylineOptions; - kmMarksEnabled?: boolean; - kmMarksStep?: number; -} - -export class InteractivePoly extends Polyline { - constructor( - latlngs: LatLngExpression[] | LatLngExpression[][], - options?: InteractivePolylineOptions - ) { - super(latlngs, options); - - this.constraintsStyle = { - ...this.constraintsStyle, - ...options.constraintsStyle - }; - this.maxMarkers = options.maxMarkers || this.maxMarkers; - - this.constrLine = new Polyline([], this.constraintsStyle); - - this.startDragHinting(); - } - - updateTouchHinter = ({ latlngs }: { latlngs: LatLngLiteral[] }): void => { - this.touchHinter.setLatLngs(latlngs); - }; - - setPoints = (latlngs: LatLng[], emitEvent = false) => { - this.setLatLngs(latlngs); - this.recreateMarkers(); - this.recalcDistance(); - this.touchHinter.setLatLngs(latlngs); - - if (emitEvent) { - this.fire("latlngschange", { latlngs }); - } - }; - - createHintMarker = (latlng: LatLng): Marker => - marker(latlng, { - draggable: false, - icon: divIcon({ - className: "leaflet-vertex-drag-helper", - iconSize: [11, 11], - iconAnchor: [6, 6] - }) - }); - - createMarker = (latlng: LatLng): Marker => - marker(latlng, { - draggable: true, - icon: divIcon({ - className: "leaflet-vertex-icon", - iconSize: [11, 11], - iconAnchor: [6, 6] - }) - }) - .on("contextmenu", this.dropMarker) - .on("drag", this.onMarkerDrag) - .on("dragstart", this.onMarkerDragStart) - .on("dragend", this.onMarkerDragEnd) - .addTo(this.markerLayer); - - recreateMarkers = () => { - this.clearAllMarkers(); - const latlngs = this.getLatLngs(); - - if (!latlngs || latlngs.length === 0) return; - - latlngs.forEach(latlng => this.markers.push(this.createMarker(latlng))); - - this.updateMarkers(); - }; - - clearAllMarkers = (): void => { - this.markerLayer.clearLayers(); - this.markers = []; - }; - - updateMarkers = (): void => { - this.showVisibleMarkers(); - }; - - showAllMarkers = (): void => { - if (!this.is_editing) return; - if (this._map.hasLayer(this.markerLayer)) return; - - this._map.addLayer(this.markerLayer); - this.fire("allvertexshow"); - }; - - hideAllMarkers = (): void => { - if (!this._map.hasLayer(this.markerLayer)) return; - - this._map.removeLayer(this.markerLayer); - this.fire("allvertexhide"); - }; - - showVisibleMarkers = (): void => { - if (!this.is_editing) return; - - const northEast = this._map.getBounds().getNorthEast(); - const southWest = this._map.getBounds().getSouthWest(); - - const { visible, hidden } = this.markers.reduce( - (obj, marker) => { - const { lat, lng } = marker.getLatLng(); - const is_hidden = - lat > northEast.lat || - lng > northEast.lng || - lat < southWest.lat || - lng < southWest.lng; - - return is_hidden - ? { ...obj, hidden: [...obj.hidden, marker] } - : { ...obj, visible: [...obj.visible, marker] }; - }, - { visible: [], hidden: [] } - ); - - if (visible.length > this.maxMarkers) return this.hideAllMarkers(); - - this.showAllMarkers(); - - visible.forEach(marker => { - if (!this.markerLayer.hasLayer(marker)) this.markerLayer.addLayer(marker); - }); - - hidden.forEach(marker => { - if (this.markerLayer.hasLayer(marker)) - this.markerLayer.removeLayer(marker); - }); - }; - - editor = { - disable: () => { - this.hideAllMarkers(); - this.is_editing = false; - this.stopDragHinting(); - this.stopDrawing(); - this.touchHinter.removeFrom(this._map); - this.fire("editordisable"); - }, - enable: () => { - this.is_editing = true; - this.showVisibleMarkers(); - this.startDragHinting(); - this.touchHinter.addTo(this._map); - - this.fire("editorenable"); - }, - continue: () => { - this.is_drawing = true; - this.drawing_direction = "forward"; - this.startDrawing(); - }, - prepend: () => { - this.is_drawing = true; - this.drawing_direction = "backward"; - this.startDrawing(); - } - }; - - moveDragHint = ({ latlng }: LeafletMouseEvent): void => { - this.hintMarker.setLatLng(latlng); - }; - - hideDragHint = (): void => { - if (this._map.hasLayer(this.hintMarker)) - this._map.removeLayer(this.hintMarker); - }; - - showDragHint = (): void => { - this._map.addLayer(this.hintMarker); - }; - - startDragHinting = (): void => { - this.touchHinter.on("mousemove", this.moveDragHint); - this.touchHinter.on("mousedown", this.startDragHintMove); - this.touchHinter.on("mouseover", this.showDragHint); - this.touchHinter.on("mouseout", this.hideDragHint); - }; - - stopDragHinting = (): void => { - this.touchHinter.off("mousemove", this.moveDragHint); - this.touchHinter.off("mousedown", this.startDragHintMove); - this.touchHinter.off("mouseover", this.showDragHint); - this.touchHinter.off("mouseout", this.hideDragHint); - }; - - startDragHintMove = (event: LeafletMouseEvent): void => { - event.originalEvent.stopPropagation(); - event.originalEvent.preventDefault(); - - if (this.is_drawing) { - this.stopDrawing(); - this.is_drawing = true; - } - - const prev = this.dragHintFindNearest(event.latlng); - - if (prev < 0) return; - - this.hint_prev_marker = prev; - - this.constrLine.setLatLngs([]).addTo(this._map); - - this._map.dragging.disable(); - - this.is_dragging = true; - - this._map.on("mousemove", this.dragHintMove); - this._map.on("mouseup", this.dragHintAddMarker); - this._map.on("mouseout", this.stopDragHintMove); - }; - - stopDragHintMove = (): void => { - this._map.dragging.enable(); - - this.constrLine.removeFrom(this._map); - - this._map.off("mousemove", this.dragHintMove); - this._map.off("mouseup", this.dragHintAddMarker); - this._map.off("mouseout", this.stopDragHintMove); - - if (this.is_drawing) this.startDrawing(); - - setTimeout(() => { - this.is_dragging = false; - }, 0); - }; - - dragHintAddMarker = ({ latlng }: LeafletMouseEvent): void => { - this.dragHintChangeDistance(this.hint_prev_marker, latlng); - - this.markers.splice( - this.hint_prev_marker + 1, - 0, - this.createMarker(latlng) - ); - this.insertLatLng(latlng, this.hint_prev_marker + 1); - this.hideDragHint(); - this.stopDragHintMove(); - }; - - dragHintChangeDistance = (index: number, current: LatLngLiteral): void => { - const prev = this.markers[index]; - const next = this.markers[index + 1]; - - const initial_distance = distKmHaversine(prev.getLatLng(), next.getLatLng()); - - const current_distance = - ((prev && distKmHaversine(prev.getLatLng(), current)) || 0) + - ((next && distKmHaversine(next.getLatLng(), current)) || 0); - - this.distance += current_distance - initial_distance; - - this.fire("distancechange", { distance: this.distance }); - }; - - dragHintFindNearest = (latlng: LatLng): any => { - const latlngs = this.getLatLngs() as LatLng[]; - - const neighbours = latlngs - .filter((current, index) => { - const next = latlngs[index + 1] as LatLng; - - return next && pointInArea(current, next, latlng); - }) - .map(el => latlngs.indexOf(el)) - .sort( - (a, b) => - distToSegment(latlngs[a], latlngs[a + 1], latlng) - - distToSegment(latlngs[b], latlngs[b + 1], latlng) - ); - - return neighbours.length > 0 ? neighbours[0] : -1; - }; - - dragHintMove = (event: LeafletMouseEvent): void => { - event.originalEvent.stopPropagation(); - event.originalEvent.preventDefault(); - - this.setConstraints([ - this.markers[this.hint_prev_marker].getLatLng(), - event.latlng, - this.markers[this.hint_prev_marker + 1].getLatLng() - ]); - }; - - onMarkerDrag = ({ target }: { target: Marker }) => { - const coords = new Array(0) - .concat( - (this.vertex_index > 0 && - this.markers[this.vertex_index - 1].getLatLng()) || - [] - ) - .concat(target.getLatLng()) - .concat( - (this.vertex_index < this.markers.length - 1 && - this.markers[this.vertex_index + 1].getLatLng()) || - [] - ); - - this.setConstraints(coords); - - this.fire("vertexdrag", { index: this.vertex_index, vertex: target }); - }; - - onMarkerDragStart = ({ target }: { target: Marker }) => { - if (this.is_drawing) { - this.stopDrawing(); - this.is_drawing = true; - } - - if (this.is_dragging) this.stopDragHintMove(); - - this.vertex_index = this.markers.indexOf(target); - - this.is_dragging = true; - this.constrLine.addTo(this._map); - - this.fire("vertexdragstart", { index: this.vertex_index, vertex: target }); - }; - - onMarkerDragEnd = ({ target }: { target: Marker }): void => { - const latlngs = this.getLatLngs() as LatLngLiteral[]; - this.markerDragChangeDistance( - this.vertex_index, - latlngs[this.vertex_index], - target.getLatLng() - ); - - this.replaceLatlng(target.getLatLng(), this.vertex_index); - - this.is_dragging = false; - this.constrLine.removeFrom(this._map); - - this.vertex_index = null; - - if (this.is_drawing) this.startDrawing(); - - this.fire("vertexdragend", { index: this.vertex_index, vertex: target }); - }; - - markerDragChangeDistance = ( - index: number, - initial: LatLngLiteral, - current: LatLngLiteral - ): void => { - const prev = index > 0 ? this.markers[index - 1] : null; - const next = - index <= this.markers.length + 1 ? this.markers[index + 1] : null; - - const initial_distance = - ((prev && distKmHaversine(prev.getLatLng(), initial)) || 0) + - ((next && distKmHaversine(next.getLatLng(), initial)) || 0); - - const current_distance = - ((prev && distKmHaversine(prev.getLatLng(), current)) || 0) + - ((next && distKmHaversine(next.getLatLng(), current)) || 0); - - this.distance += current_distance - initial_distance; - - this.fire("distancechange", { distance: this.distance }); - }; - - startDrawing = (): void => { - this.is_drawing = true; - this.setConstraints([]); - this.constrLine.addTo(this._map); - this._map.on("mousemove", this.onDrawingMove); - this._map.on("click", this.onDrawingClick); - }; - - stopDrawing = (): void => { - this.constrLine.removeFrom(this._map); - this._map.off("mousemove", this.onDrawingMove); - this._map.off("click", this.onDrawingClick); - this.is_drawing = false; - }; - - onDrawingMove = ({ latlng }: LeafletMouseEvent): void => { - if (this.markers.length === 0) { - this.setConstraints([]); - return; - } - - if (!this._map.hasLayer(this.constrLine)) - this._map.addLayer(this.constrLine); - - const marker = - this.drawing_direction === "forward" - ? this.markers[this.markers.length - 1] - : this.markers[0]; - - this.setConstraints([latlng, marker.getLatLng()]); - }; - - onDrawingClick = (event: LeafletMouseEvent): void => { - if (this.is_dragging) return; - - const { latlng } = event; - - this.stopDrawing(); - - const latlngs = this.getLatLngs() as any[]; - - this.drawingChangeDistance(latlng); - - if (this.drawing_direction === "forward") { - latlngs.push(latlng); - this.markers.push(this.createMarker(latlng)); - } else { - latlngs.unshift(latlng); - this.markers.unshift(this.createMarker(latlng)); - } - - this.setLatLngs(latlngs); - this.fire("latlngschange", { latlngs }); - this.showVisibleMarkers(); - this.startDrawing(); - }; - - drawingChangeDistance = (latlng: LatLngLiteral): void => { - const latlngs = this.getLatLngs() as LatLngLiteral[]; - - if (latlngs.length < 1) { - this.distance = 0; - this.fire("distancechange", { distance: this.distance }); - return; - } - - const point = - this.drawing_direction === "forward" - ? latlngs[latlngs.length - 1] - : latlngs[0]; - - this.distance += distKmHaversine(point, latlng); - this.fire("distancechange", { distance: this.distance }); - }; - - replaceLatlng = (latlng: LatLng, index: number): void => { - const latlngs = this.getLatLngs() as LatLngLiteral[]; - latlngs.splice(index, 1, latlng); - this.setLatLngs(latlngs); - this.fire("latlngschange", { latlngs }); - }; - - insertLatLng = (latlng, index): void => { - const latlngs = this.getLatLngs(); - latlngs.splice(index, 0, latlng); - this.setLatLngs(latlngs); - this.fire("latlngschange", { latlngs }); - }; - - setConstraints = (coords: LatLng[]) => { - this.constrLine.setLatLngs(coords); - }; - - dropMarker = ({ target }: LeafletMouseEvent): void => { - const index = this.markers.indexOf(target); - const latlngs = this.getLatLngs(); - - if (typeof index === "undefined" || latlngs.length <= 2) return; - - this.dropMarkerDistanceChange(index); - this._map.removeLayer(this.markers[index]); - this.markers.splice(index, 1); - latlngs.splice(index, 1); - - this.setLatLngs(latlngs); - this.fire("latlngschange", { latlngs }); - }; - - dropMarkerDistanceChange = (index: number): void => { - const latlngs = this.getLatLngs() as LatLngLiteral[]; - - const prev = index > 0 ? latlngs[index - 1] : null; - const current = latlngs[index]; - const next = index <= latlngs.length + 1 ? latlngs[index + 1] : null; - - const initial_distance = - ((prev && distKmHaversine(prev, current)) || 0) + - ((next && distKmHaversine(next, current)) || 0); - - const current_distance = (prev && next && distKmHaversine(prev, next)) || 0; - - this.distance += current_distance - initial_distance; - - this.fire("distancechange", { distance: this.distance }); - }; - - recalcDistance = () => { - const latlngs = this.getLatLngs() as LatLngLiteral[]; - this.distance = getPolyLength(latlngs); - - this.fire("distancechange", { distance: this.distance }); - }; - - markers: Marker[] = []; - maxMarkers: InteractivePolylineOptions["maxMarkers"] = 2; - markerLayer: LayerGroup = new LayerGroup(); - - constraintsStyle: InteractivePolylineOptions["constraintsStyle"] = { - weight: 6, - color: "red", - dashArray: "10, 12", - opacity: 0.5, - interactive: false - }; - - touchHinter: Polyline = new Polyline([], { - weight: 24, - smoothFactor: 3, - className: "touch-hinter-poly" - }); - - hintMarker: Marker = this.createHintMarker(latLng({ lat: 0, lng: 0 })); - - constrLine: Polyline; - - is_editing: boolean = true; - is_dragging: boolean = false; - is_drawing: boolean = false; - - drawing_direction: "forward" | "backward" = "forward"; - vertex_index?: number = null; - - hint_prev_marker: number = null; - distance: number = 0; -} - -InteractivePoly.addInitHook(function() { - this.once("add", event => { - if (event.target instanceof InteractivePoly) { - this.map = event.target._map; - - this.markerLayer.addTo(event.target._map); - this.hintMarker.addTo(event.target._map); - this.constrLine.addTo(event.target._map); - this.touchHinter.addTo(event.target._map); - - this.map.on("moveend", this.updateMarkers); - - this.on("latlngschange", this.updateTouchHinter); - - if (window.innerWidth < 768) { - this.touchHinter.setStyle({ weight: 32 }); - } - } - }); - - this.once("remove", event => { - if (event.target instanceof InteractivePoly) { - this.markerLayer.removeFrom(this._map); - this.hintMarker.removeFrom(this._map); - this.constrLine.removeFrom(this._map); - this.touchHinter.removeFrom(this._map); - - this.map.off("moveend", this.updateMarkers); - } - }); -}); - -// export const InteractivePoly = Component; -/* - events: - vertexdragstart, - vertexdragend, - vertexdrag, - - allvertexhide - allvertexshow - - editordisable - editorenable - - distancechange - - latlngschange - */ diff --git a/src/_modules/KmMarks.ts b/src/_modules/KmMarks.ts deleted file mode 100644 index d44aa70..0000000 --- a/src/_modules/KmMarks.ts +++ /dev/null @@ -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, distKmHaversine } 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 = distKmHaversine(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: ` -
- ${distance} -
- `, - 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: ` -
- ${parseFloat(distance.toFixed(1))} -
- `, - 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; diff --git a/src/_modules/Map.ts b/src/_modules/Map.ts deleted file mode 100644 index 25ceece..0000000 --- a/src/_modules/Map.ts +++ /dev/null @@ -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); - } -} diff --git a/src/_modules/Poly.ts b/src/_modules/Poly.ts deleted file mode 100644 index fa10316..0000000 --- a/src/_modules/Poly.ts +++ /dev/null @@ -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): void => { - if (!latlngs || latlngs.length <= 1) return; - this.poly.setPoints(latlngs); - }; - - pushPoints = (latlngs: Array): 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 => this.latlngs; - - get latlngs(): Array { - 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']; -} diff --git a/src/_modules/Router.ts b/src/_modules/Router.ts deleted file mode 100644 index a8cf47a..0000000 --- a/src/_modules/Router.ts +++ /dev/null @@ -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 = []; - setIsRouting: Props['setIsRouting']; - lockMapClicks: Props['lockMapClicks']; - setRouterPoints: Props['setRouterPoints']; - pushPolyPoints: Props['pushPolyPoints']; - router: Routing; -} diff --git a/src/_modules/Sticker.tsx b/src/_modules/Sticker.tsx deleted file mode 100644 index ceec2c1..0000000 --- a/src/_modules/Sticker.tsx +++ /dev/null @@ -1,236 +0,0 @@ -import { Map, Marker, marker } from 'leaflet'; -import React from 'react'; -import { DomMarker } from '~/utils/DomMarker'; - -import { STICKERS } from '~/constants/stickers'; -import 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( - -
{ this.stickerArrow = el; }} - /> -
{ this.stickerImage = el; }} - > - -
-
-
- , - 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']; -} diff --git a/src/_modules/Stickers.ts b/src/_modules/Stickers.ts deleted file mode 100644 index 4b42d74..0000000 --- a/src/_modules/Stickers.ts +++ /dev/null @@ -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 => 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 = []; - layer: FeatureGroup = new FeatureGroup(); - - triggerOnChange: Props['triggerOnChange']; - lockMapClicks: Props['lockMapClicks']; -} diff --git a/src/components/dialogs/MapListDialog.tsx b/src/components/dialogs/MapListDialog.tsx index 66d296d..a351192 100644 --- a/src/components/dialogs/MapListDialog.tsx +++ b/src/components/dialogs/MapListDialog.tsx @@ -32,20 +32,11 @@ const mapStateToProps = ({ user: { role }, }, }: IState) => { - if (routes.filter.max >= 9999) { - return { - routes, - editing, - ready: false, - role, - }; - } - return { role, routes, editing, - ready: true, + ready: routes.filter.max < 9999, }; }; diff --git a/src/components/dialogs/RouterDialog.tsx b/src/components/dialogs/RouterDialog.tsx index 467f91a..d75c166 100644 --- a/src/components/dialogs/RouterDialog.tsx +++ b/src/components/dialogs/RouterDialog.tsx @@ -89,18 +89,17 @@ const mapDispatchToProps = { editorRouterSubmit: EDITOR_ACTIONS.editorRouterSubmit, }; -type Props = ReturnType & typeof mapDispatchToProps & { }; +type Props = ReturnType & typeof mapDispatchToProps & {}; const RouterDialogUnconnected: FC = ({ editor: { router: { waypoints }, - is_routing, }, editorRouterCancel, editorRouterSubmit, }) => (
-
+
{!waypoints.length && noPoints({ editorRouterCancel })} {waypoints.length === 1 && firstPoint({ editorRouterCancel })} diff --git a/src/components/maps/RouteRowDrop.tsx b/src/components/maps/RouteRowDrop.tsx index e85d756..5b03e4f 100644 --- a/src/components/maps/RouteRowDrop.tsx +++ b/src/components/maps/RouteRowDrop.tsx @@ -1,29 +1,25 @@ // @flow -import React from 'react'; -import { Icon } from '~/components/panels/Icon'; -import { MapListDialog } from "~/components/dialogs/MapListDialog"; -import { Tooltip } from "~/components/panels/Tooltip"; -import { ReactElement } from "react"; +import React, { FC, memo } from 'react'; +import { MapListDialog } from '~/components/dialogs/MapListDialog'; +import { ReactElement } from 'react'; interface Props { - address: string, - stopEditing: typeof MapListDialog.stopEditing, - dropRoute: typeof MapListDialog.dropRoute, + address: string; + stopEditing: typeof MapListDialog.stopEditing; + dropRoute: typeof MapListDialog.dropRoute; } -export const RouteRowDrop = ({ - address, stopEditing, dropRoute, -}: Props): ReactElement => ( -
-
+export const RouteRowDrop: FC = memo(({ address, stopEditing, dropRoute }) => ( +
+
-
Удалить
-
Отмена
+
+ Удалить +
+
+ Отмена +
-); +)); diff --git a/src/components/panels/DistanceBar.tsx b/src/components/panels/DistanceBar.tsx index 866537d..5c33ead 100644 --- a/src/components/panels/DistanceBar.tsx +++ b/src/components/panels/DistanceBar.tsx @@ -4,27 +4,24 @@ import { Icon } from '~/components/panels/Icon'; import { connect } from 'react-redux'; import Slider from 'rc-slider/lib/Slider'; import { editorSetSpeed } from '~/redux/editor/actions'; -import { Tooltip } from "~/components/panels/Tooltip"; -import { isMobile } from "~/utils/window"; +import { Tooltip } from '~/components/panels/Tooltip'; +import { isMobile } from '~/utils/window'; import { IState } from '~/redux/store'; +import pick from 'ramda/es/pick'; +import { selectEditor } from '~/redux/editor/selectors'; -function mapStateToProps(state) { - const { - editor: { distance, estimated, speed }, - }: IState = state; - - return { distance, estimated, speed }; -} +const mapStateToProps = (state: IState) => + pick(['distance', 'estimated', 'speed'], selectEditor(state)); const mapDispatchToProps = { editorSetSpeed }; type Props = ReturnType & typeof mapDispatchToProps & {}; interface State { - dialogOpened: boolean, + dialogOpened: boolean; } -class Component extends React.PureComponent { +class DistanceBarUnconnected extends React.PureComponent { constructor(props) { super(props); this.state = { @@ -36,10 +33,15 @@ class Component extends React.PureComponent { min: number = 5; max: number = 30; - marks: { [x: number]: string } = [...Array((Math.floor(this.max - this.min) / this.step) + 1)].reduce((obj, el, index) => ({ - ...obj, - [this.min + (index * this.step)]: String(this.min + (index * this.step)), - }), { }); + marks: { [x: number]: string } = [ + ...Array(Math.floor(this.max - this.min) / this.step + 1), + ].reduce( + (obj, el, index) => ({ + ...obj, + [this.min + index * this.step]: String(this.min + index * this.step), + }), + {} + ); toggleDialog = () => { if (isMobile()) return; @@ -51,10 +53,12 @@ class Component extends React.PureComponent { const { props: { distance, estimated, speed }, state: { dialogOpened }, - min, max, step, marks, + min, + max, + step, + marks, } = this; - return (
@@ -65,8 +69,7 @@ class Component extends React.PureComponent {
{toHours(estimated)}
- { - dialogOpened && + {dialogOpened && (
{ />
- } + )}
); } } -export const DistanceBar = connect( - mapStateToProps, - mapDispatchToProps -)(Component); +export const DistanceBar = connect(mapStateToProps, mapDispatchToProps)(DistanceBarUnconnected); diff --git a/src/components/panels/EditorPanel.tsx b/src/components/panels/EditorPanel.tsx index ef4bf4d..54382b0 100644 --- a/src/components/panels/EditorPanel.tsx +++ b/src/components/panels/EditorPanel.tsx @@ -4,7 +4,6 @@ import classnames from 'classnames'; import { Icon } from '~/components/panels/Icon'; import { EditorDialog } from '~/components/panels/EditorDialog'; -import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { editorSetMode, @@ -16,10 +15,10 @@ import { import { Tooltip } from '~/components/panels/Tooltip'; import { IState } from '~/redux/store'; import { selectEditor } from '~/redux/editor/selectors'; +import pick from 'ramda/es/pick'; -const mapStateToProps = (state: IState) => ({ - editor: selectEditor(state), -}); +const mapStateToProps = (state: IState) => + pick(['mode', 'changed', 'editing', 'features'], selectEditor(state)); const mapDispatchToProps = { editorSetMode, @@ -54,18 +53,15 @@ class EditorPanelUnconnected extends PureComponent { startRouterMode = () => this.props.editorSetMode(MODES.ROUTER); startTrashMode = () => this.props.editorSetMode(MODES.TRASH); startSaveMode = () => { - // if (!this.props.changed) return; this.props.editorSetMode(MODES.SAVE); }; render() { const { - editor: { - mode, - changed, - editing, - features: { routing }, - }, + mode, + changed, + editing, + features: { routing }, } = this.props; return ( diff --git a/src/components/panels/Icon.tsx b/src/components/panels/Icon.tsx index 62354f1..a381018 100644 --- a/src/components/panels/Icon.tsx +++ b/src/components/panels/Icon.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { memo } from 'react'; -export const Icon = ({ icon, size = 32 }: { icon: string, size?: number }) => ( +export const Icon = memo(({ icon, size = 32 }: { icon: string; size?: number }) => ( @@ -9,5 +9,4 @@ export const Icon = ({ icon, size = 32 }: { icon: string, size?: number }) => ( -); - +)); diff --git a/src/components/panels/TopLeftPanel.tsx b/src/components/panels/TopLeftPanel.tsx index 44acce7..aa7b902 100644 --- a/src/components/panels/TopLeftPanel.tsx +++ b/src/components/panels/TopLeftPanel.tsx @@ -1,10 +1,10 @@ -import React from 'react'; +import React, { memo } from 'react'; import { UserLocation } from '~/components/UserLocation'; import { DistanceBar } from '~/components/panels/DistanceBar'; -export const TopLeftPanel = () => ( +export const TopLeftPanel = memo(() => (
-); +)); diff --git a/src/components/panels/TopRightPanel.tsx b/src/components/panels/TopRightPanel.tsx index 9394433..5b6278c 100644 --- a/src/components/panels/TopRightPanel.tsx +++ b/src/components/panels/TopRightPanel.tsx @@ -9,11 +9,14 @@ import { MODES } from '~/constants/modes'; import { Tooltip } from '~/components/panels/Tooltip'; import { selectMap } from '~/redux/map/selectors'; import { selectEditor } from '~/redux/editor/selectors'; +import { IState } from '~/redux/store'; -const mapStateToProps = state => ({ - map: selectMap(state), - editor: selectEditor(state), -}); +const mapStateToProps = (state: IState) => { + const { provider, logo } = selectMap(state); + const { markers_shown, editing } = selectEditor(state); + + return { provider, logo, markers_shown, editing }; +}; const mapDispatchToProps = { editorSetMode: EDITOR_ACTIONS.editorSetMode, @@ -22,8 +25,10 @@ const mapDispatchToProps = { type Props = ReturnType & typeof mapDispatchToProps & {}; const TopRightPanelUnconnected = ({ - map: { provider, logo }, - editor: { markers_shown, editing }, + provider, + logo, + markers_shown, + editing, editorSetMode, }: Props) => { const startProviderMode = useCallback(() => editorSetMode(MODES.PROVIDER), [editorSetMode]); diff --git a/src/components/panels/UserPanel.tsx b/src/components/panels/UserPanel.tsx index d4049fc..112e0f4 100644 --- a/src/components/panels/UserPanel.tsx +++ b/src/components/panels/UserPanel.tsx @@ -19,21 +19,18 @@ import { CLIENT } from '~/config/frontend'; import { DIALOGS, TABS } from '~/constants/dialogs'; import { Tooltip } from '~/components/panels/Tooltip'; import { TitleDialog } from '~/components/dialogs/TitleDialog'; +import { IState } from '~/redux/store'; const mapStateToProps = ({ user: { user }, editor: { dialog, dialog_active }, map: { route, stickers }, -}) => ({ - editor: { - dialog, - dialog_active, - }, - user: { user }, - map: { - route, - stickers, - } +}: IState) => ({ + dialog, + dialog_active, + user, + route, + stickers, }); const mapDispatchToProps = { @@ -100,7 +97,7 @@ export class UserPanelUnconnected extends PureComponent { openAppInfoDialog = () => { this.setMenuOpened(); this.props.editorSetDialog(DIALOGS.APP_INFO); - this.props.editorSetDialogActive(this.props.editor.dialog !== DIALOGS.APP_INFO); + this.props.editorSetDialogActive(this.props.dialog !== DIALOGS.APP_INFO); }; openOauthFrame = () => { @@ -118,7 +115,7 @@ export class UserPanelUnconnected extends PureComponent { render() { const { - props: { user: { user }, editor: { dialog, dialog_active }, map: { route, stickers } }, + props: { user, dialog, dialog_active, route, stickers }, state: { menuOpened }, } = this; diff --git a/src/components/user/UserButton.tsx b/src/components/user/UserButton.tsx index 2ab1bf2..d013294 100644 --- a/src/components/user/UserButton.tsx +++ b/src/components/user/UserButton.tsx @@ -1,25 +1,22 @@ // @flow -import React from "react"; -import { UserPicture } from "~/components/user/UserPicture"; -import { IUser } from "~/constants/auth"; +import React, { FC, memo } from 'react'; +import { UserPicture } from '~/components/user/UserPicture'; +import { IUser } from '~/constants/auth'; interface Props { user: IUser; setMenuOpened: () => void; } -export const UserButton = ({ - setMenuOpened, - user: { uid, photo, name } -}: Props) => ( +export const UserButton: FC = memo(({ setMenuOpened, user: { uid, photo, name } }) => (
-
{name || uid || "..."}
-
{uid || "пользователь"}
+
{name || uid || '...'}
+
{uid || 'пользователь'}
-); +)); diff --git a/src/containers/App.tsx b/src/containers/App.tsx index e7c7c85..3be17a4 100644 --- a/src/containers/App.tsx +++ b/src/containers/App.tsx @@ -32,7 +32,7 @@ type Props = { editorSetDialogActive: typeof editorSetDialogActive; }; -const Component = (props: Props) => ( +const AppUnconnected = (props: Props) => (
@@ -72,6 +72,8 @@ const mapStateToProps = ({ set, }); -const mapDispatchToProps = dispatch => - bindActionCreators({ editorHideRenderer, editorSetDialogActive }, dispatch); -export const App = connect(mapStateToProps, mapDispatchToProps)(hot(module)(Component)); +const mapDispatchToProps = { editorHideRenderer, editorSetDialogActive }; + +const App = connect(mapStateToProps, mapDispatchToProps)(hot(module)(AppUnconnected)); + +export { App }; diff --git a/src/containers/LeftDialog.tsx b/src/containers/LeftDialog.tsx index f22a993..4455738 100644 --- a/src/containers/LeftDialog.tsx +++ b/src/containers/LeftDialog.tsx @@ -1,4 +1,4 @@ -import React, { createElement } from 'react'; +import React, { createElement, FC, memo } from 'react'; import { DIALOGS, IDialogs } from '~/constants/dialogs'; import classnames from 'classnames'; import { AppInfoDialog } from '~/components/dialogs/AppInfoDialog'; @@ -17,7 +17,7 @@ const LEFT_DIALOGS = { [DIALOGS.APP_INFO]: AppInfoDialog, }; -const LeftDialog = ({ dialog, dialog_active, editorSetDialogActive }: Props) => ( +const LeftDialog: FC = memo(({ dialog, dialog_active, editorSetDialogActive }) => ( {Object.keys(LEFT_DIALOGS).map(item => (
> {dialog && LEFT_DIALOGS[item] && createElement(LEFT_DIALOGS[item], {})} -
editorSetDialogActive(false)}> +
editorSetDialogActive(false)} + >
-
editorSetDialogActive(false)}> +
editorSetDialogActive(false)} + >
))} -); +)); export { LeftDialog }; diff --git a/src/containers/map/Route/index.tsx b/src/containers/map/Route/index.tsx index 2fb157e..f7c0a54 100644 --- a/src/containers/map/Route/index.tsx +++ b/src/containers/map/Route/index.tsx @@ -1,6 +1,6 @@ import React, { FC, useEffect, memo, useState, useCallback } from 'react'; import { IMapRoute } from '../../../redux/map/types'; -import { InteractivePoly } from '~/utils/polyline'; +import { InteractivePoly } from '~/utils/map/InteractivePoly'; import { isMobile } from '~/utils/window'; import { LatLng, Map, LeafletEvent } from 'leaflet'; import { selectEditor } from '~/redux/editor/selectors'; diff --git a/src/containers/map/Router/index.tsx b/src/containers/map/Router/index.tsx index ad25411..a2dd2dd 100644 --- a/src/containers/map/Router/index.tsx +++ b/src/containers/map/Router/index.tsx @@ -1,6 +1,6 @@ -import React, { FC, useEffect, useMemo, useCallback, memo } from 'react'; +import { FC, useEffect, useCallback, memo } from 'react'; import pick from 'ramda/es/pick'; -import { OsrmRouter } from '~/utils/osrm'; +import { OsrmRouter } from '~/utils/map/OsrmRouter'; import { connect } from 'react-redux'; import { selectMap } from '~/redux/map/selectors'; import { selectEditorRouter, selectEditorMode } from '~/redux/editor/selectors'; diff --git a/src/containers/map/Sticker/index.tsx b/src/containers/map/Sticker/index.tsx index c8567fb..a128a26 100644 --- a/src/containers/map/Sticker/index.tsx +++ b/src/containers/map/Sticker/index.tsx @@ -4,7 +4,7 @@ import { IStickerDump } from '~/redux/map/types'; import { STICKERS } from '~/constants/stickers'; import { StickerDesc } from '~/components/StickerDesc'; import classNames from 'classnames'; -import { DomMarker } from '~/utils/DomMarker'; +import { DomMarker } from '~/utils/map/DomMarker'; import { createPortal } from 'react-dom'; import { MapContainer, MainMap } from '~/constants/map'; diff --git a/src/redux/editor/sagas.ts b/src/redux/editor/sagas.ts index 24ddb3a..e0c1ba7 100644 --- a/src/redux/editor/sagas.ts +++ b/src/redux/editor/sagas.ts @@ -42,7 +42,7 @@ import { LOGOS } from '~/constants/logos'; import { loadMapFromPath } from '../map/sagas'; import { mapClicked, mapSetRoute } from '../map/actions'; import { MAP_ACTIONS } from '../map/constants'; -import { OsrmRouter } from '~/utils/osrm'; +import { OsrmRouter } from '~/utils/map/OsrmRouter'; import path from 'ramda/es/path'; import { MainMap } from '~/constants/map'; import { EDITOR_INITIAL_STATE } from '.'; @@ -236,7 +236,7 @@ function* mapClick({ latlng }: ReturnType) { function* routerSubmit() { const route: ReturnType = yield select(selectMapRoute); - const latlngs = path(['_routes', 0, 'coordinates'], OsrmRouter); + const latlngs: LatLng[] = path(['_routes', 0, 'coordinates'], OsrmRouter); const coordinates = simplify({ map: MainMap, latlngs }); diff --git a/src/utils/arrow.ts b/src/utils/arrow.ts index ae52e2a..bfbc909 100644 --- a/src/utils/arrow.ts +++ b/src/utils/arrow.ts @@ -23,11 +23,6 @@ export const createArrow = (latlng: LatLngLiteral, angle: number): Marker => mar export const arrowClusterIcon = (cluster): DivIcon => { const markers = cluster.getAllChildMarkers(); - // search for nearest marker to cluster (slow) - // const nearest = markers.sort((a, b) => ( - // dist2(a.getLatLng(), cluster.getLatLng()) - dist2(b.getLatLng(), cluster.getLatLng()) - // )); - // faster way cluster.setLatLng(markers[markers.length - 1].getLatLng()); return markers[markers.length - 1].options.icon; diff --git a/src/_modules/Arrows.ts b/src/utils/map/Arrows.ts similarity index 100% rename from src/_modules/Arrows.ts rename to src/utils/map/Arrows.ts diff --git a/src/utils/DomMarker.js b/src/utils/map/DomMarker.js similarity index 94% rename from src/utils/DomMarker.js rename to src/utils/map/DomMarker.js index a2f2d1e..a8ca9d0 100644 --- a/src/utils/DomMarker.js +++ b/src/utils/map/DomMarker.js @@ -15,7 +15,7 @@ export const DomMarker = DivIcon.extend({ this._setIconStyles(element, 'icon'); - return element; + return element; } }); diff --git a/src/utils/polyline.ts b/src/utils/map/InteractivePoly.ts similarity index 99% rename from src/utils/polyline.ts rename to src/utils/map/InteractivePoly.ts index f209dd2..c2037ba 100644 --- a/src/utils/polyline.ts +++ b/src/utils/map/InteractivePoly.ts @@ -576,7 +576,6 @@ InteractivePoly.addInitHook(function() { }); }); -// export const InteractivePoly = Component; /* events: vertexdragstart, diff --git a/src/utils/osrm.ts b/src/utils/map/OsrmRouter.ts similarity index 96% rename from src/utils/osrm.ts rename to src/utils/map/OsrmRouter.ts index 9f12dc8..3e30da2 100644 --- a/src/utils/osrm.ts +++ b/src/utils/map/OsrmRouter.ts @@ -1,7 +1,7 @@ import { Marker } from 'leaflet'; import * as Routing from 'leaflet-routing-machine/src/index'; import { CLIENT } from '~/config/frontend'; -import { DomMarker } from '~/utils/DomMarker'; +import { DomMarker } from '~/utils/map/DomMarker'; import { MainMap } from '~/constants/map'; const createWaypointMarker = (): DomMarker => { diff --git a/src/utils/clusterIcon.ts b/src/utils/map/clusterIcon.ts similarity index 100% rename from src/utils/clusterIcon.ts rename to src/utils/map/clusterIcon.ts