From 628b96c4ab0e98cd83c7cdc9e52c1366dd858f8e Mon Sep 17 00:00:00 2001 From: muerwre Date: Wed, 20 Feb 2019 17:52:42 +0700 Subject: [PATCH] more typescripting --- src/components/StickerDesc.tsx | 2 +- src/components/StickerIcon.tsx | 2 +- src/constants/stickers.ts | 4 +- src/modules/Editor.ts | 59 +++++++++++++++--------- src/modules/Map.ts | 26 +++++------ src/modules/Sticker.tsx | 84 ++++++++++++++++++++++------------ src/modules/Stickers.ts | 70 +++++++++++++++------------- 7 files changed, 144 insertions(+), 103 deletions(-) diff --git a/src/components/StickerDesc.tsx b/src/components/StickerDesc.tsx index 5fcf697..43a146b 100644 --- a/src/components/StickerDesc.tsx +++ b/src/components/StickerDesc.tsx @@ -3,7 +3,7 @@ import classnames from 'classnames'; interface Props { value: string; - onChange: EventHandlerNonNull; + onChange: (text: string) => void; } type State = { diff --git a/src/components/StickerIcon.tsx b/src/components/StickerIcon.tsx index 5376bde..27e499b 100644 --- a/src/components/StickerIcon.tsx +++ b/src/components/StickerIcon.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { ISticker, STICKERS } from '$constants/stickers'; +import { STICKERS } from '$constants/stickers'; type Props = { set: string, diff --git a/src/constants/stickers.ts b/src/constants/stickers.ts index 2711f7e..154db76 100644 --- a/src/constants/stickers.ts +++ b/src/constants/stickers.ts @@ -1,6 +1,6 @@ // Стикеры // import L from "leaflet"; -export interface ISticker { +export interface IStickerItem { off: number, title: string, title_long: string, @@ -11,7 +11,7 @@ export interface IStickerPack { url: string, size: number, layers: { - [x: string]: ISticker, + [x: string]: IStickerItem, } } diff --git a/src/modules/Editor.ts b/src/modules/Editor.ts index f75288a..6f3579b 100644 --- a/src/modules/Editor.ts +++ b/src/modules/Editor.ts @@ -1,7 +1,7 @@ import { Map } from '$modules/Map'; import { Poly } from '$modules/Poly'; import { MODES } from '$constants/modes'; -import { Stickers } from '$modules/Stickers'; +import { ILatLng, Stickers } from '$modules/Stickers'; import { Router } from '$modules/Router'; import { DEFAULT_LOGO, ILogos, LOGOS } from '$constants/logos'; @@ -32,17 +32,18 @@ interface IEditor { router: Router; logo: keyof ILogos; - owner: string; + owner: { id: string }; initialData: { version: number, title: string, - owner: string, + owner: { id: string }, address: string, path: any, route: any, stickers: any, provider: string, is_public: boolean, + logo: string, }; activeSticker: IRootState['activeSticker']; mode: IRootState['mode']; @@ -54,7 +55,9 @@ interface IEditor { toggle?: () => any, } }; - clickHandlers; + clickHandlers: { + [x: string]: (event) => void + }; user: IUser; } @@ -63,7 +66,6 @@ export class Editor implements IEditor { this.logo = DEFAULT_LOGO; this.owner = null; this.map = new Map({ container: 'map' }); - this.initialData = {}; this.activeSticker = {}; this.mode = MODES.NONE; this.provider = PROVIDERS[DEFAULT_PROVIDER]; @@ -126,20 +128,31 @@ export class Editor implements IEditor { map.addEventListener('dragstop', () => lockMapClicks(false)); } - map; - poly; - stickers; - router; + map: IEditor['map']; + poly: IEditor['poly']; + stickers: IEditor['stickers']; + router: IEditor['router']; - logo = DEFAULT_LOGO; - owner = null; - initialData; - activeSticker; - mode; - provider; - switches; - clickHandlers; - user = DEFAULT_USER; + 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: null, + 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; @@ -192,7 +205,7 @@ export class Editor implements IEditor { createStickerOnClick = (e) => { if (!e || !e.latlng || !this.activeSticker) return; - const { latlng } = e; + const { latlng }: { latlng: ILatLng } = e; this.stickers.createSticker({ latlng, sticker: this.activeSticker.sticker, set: this.activeSticker.set }); this.setActiveSticker(null); @@ -281,7 +294,7 @@ export class Editor implements IEditor { setData = ({ route = [], stickers = [], owner, title, address, provider = DEFAULT_PROVIDER, logo = DEFAULT_LOGO, is_public, - }) => { + }: IEditor['initialData']) => { this.setTitle(title || ''); const { id } = this.getUser(); @@ -308,6 +321,7 @@ export class Editor implements IEditor { this.setPublic(is_public); this.setLogo((logo && LOGOS[DEFAULT_LOGO] && logo) || DEFAULT_LOGO); this.setProvider((provider && PROVIDERS[provider] && provider) || DEFAULT_PROVIDER); + if (owner) this.owner = owner; }; @@ -321,19 +335,20 @@ export class Editor implements IEditor { setInitialData = () => { const { path } = getUrlData(); const { id } = this.getUser(); - const { is_public } = this.getState(); + const { is_public, logo } = this.getState(); const { route, stickers, provider } = this.dumpData(); this.initialData = { version: 2, title: this.getTitle(), owner: this.owner, - address: (this.owner === id ? path : null), + address: (this.owner.id === id ? path : null), path, route, stickers, provider, is_public, + logo, }; }; diff --git a/src/modules/Map.ts b/src/modules/Map.ts index 7afcda2..95059cc 100644 --- a/src/modules/Map.ts +++ b/src/modules/Map.ts @@ -9,30 +9,26 @@ import 'leaflet/dist/leaflet.css'; import { PROVIDER } from '$config/frontend'; import { DEFAULT_PROVIDER, PROVIDERS } from '$constants/providers'; -interface IMap { - map: MapInterface; - tileLayer: TileLayer; - setProvider: (provider: string) => void; +interface Props { + container: string } -export class Map implements IMap { - constructor({ container }) { +export class Map { + constructor({ container }: Props) { this.map = map(container).setView([55.0153275, 82.9071235], 13); // todo: change coords? - this.tileLayer = tileLayer(PROVIDER.url, { - attribution: 'Независимое Велосообщество', - maxNativeZoom: 18, - maxZoom: 18, - }); - this.tileLayer.addTo(this.map); } - map; - tileLayer; + map: MapInterface; + tileLayer: TileLayer = tileLayer(PROVIDER.url, { + attribution: 'Независимое Велосообщество', + maxNativeZoom: 18, + maxZoom: 18, + }); - setProvider = (provider) => { + setProvider = (provider: string): void => { const { url } = (provider && PROVIDERS[provider] && PROVIDERS[provider]) || PROVIDERS[DEFAULT_PROVIDER]; this.tileLayer.setUrl(url); diff --git a/src/modules/Sticker.tsx b/src/modules/Sticker.tsx index e39fe96..c8f11d9 100644 --- a/src/modules/Sticker.tsx +++ b/src/modules/Sticker.tsx @@ -7,6 +7,8 @@ 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/reducer"; const getX = e => ( e.touches && e.touches.length > 0 @@ -14,7 +16,16 @@ const getX = e => ( : { pageX: e.pageX, pageY: e.pageY } ); -interface ISticker { + +export interface IStickerDump { + latlng: ILatLng, + sticker: string, + set: IRootState['activeSticker']['set'], + angle?: number, + text?: string, +} + +interface IStickerson { element: HTMLDivElement; stickerImage: HTMLDivElement; stickerArrow: HTMLDivElement; @@ -32,10 +43,22 @@ interface ISticker { lockMapClicks: (x: boolean) => void; } -export class Sticker implements ISticker { +interface Props { + latlng: ILatLng; + deleteSticker: (sticker: this) => void; + map: Map; + lockMapClicks: (status: boolean) => void; + sticker: IRootState['activeSticker']['sticker']; + set: IRootState['activeSticker']['set']; + triggerOnChange: () => void; + angle?: number; + text?: string; +} + +export class Sticker { constructor({ latlng, deleteSticker, map, lockMapClicks, sticker, set, triggerOnChange, angle = 2.2, text = '', - }) { + }: Props) { this.text = text; this.latlng = latlng; this.angle = parseFloat(((angle && (angle % Math.PI)) || 2.2).toFixed(2)); @@ -97,15 +120,15 @@ export class Sticker implements ISticker { this.setAngle(this.angle); } - setText = text => { + setText = (text: Props['text']): void => { this.text = text; }; - onDelete = () => { + onDelete = (): void => { if (!this.isDragging) this.deleteSticker(this); }; - onDragStart = e => { + onDragStart = (e): void => { this.preventPropagations(e); this.marker.dragging.disable(); @@ -121,14 +144,14 @@ export class Sticker implements ISticker { // this.marker.disableEdit(); }; - preventPropagations = e => { + preventPropagations = (e): void => { if (!e || !e.stopPropagation) return; e.stopPropagation(); e.preventDefault(); }; - onDragStop = e => { + onDragStop = (e): void => { this.preventPropagations(e); this.marker.dragging.enable(); @@ -144,20 +167,21 @@ export class Sticker implements ISticker { this.lockMapClicks(false); }; - onDrag = e => { + onDrag = (e: DragEvent): void => { this.preventPropagations(e); this.estimateAngle(e); }; - 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 => { + setAngle = (angle: Props['angle']): void => { const direction = getLabelDirection(angle); if (direction !== this.direction) { @@ -176,7 +200,7 @@ export class Sticker implements ISticker { this.stickerArrow.style.transform = `rotate(${angle + Math.PI}rad)`; }; - dumpData = () => ({ + dumpData = (): IStickerDump => ({ angle: this.angle, latlng: { ...this.marker.getLatLng() }, sticker: this.sticker, @@ -184,27 +208,29 @@ export class Sticker implements ISticker { text: this.text, }); - stopEditing = () => { + stopEditing = (): void => { this.element.className = 'sticker-container inactive'; }; - startEditing = () => { + startEditing = (): void => { this.element.className = 'sticker-container'; }; - element = document.createElement('div'); - stickerImage; - stickerArrow; - marker; - text; - latlng; - angle; - isDragging = false; - map; - sticker; - set; - triggerOnChange; - direction; - deleteSticker; - lockMapClicks; + element: HTMLDivElement = document.createElement('div'); + stickerImage: HTMLDivElement; + stickerArrow: HTMLDivElement; + marker: Marker; + isDragging: boolean = false; + direction: string; + + 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 index dc69c42..df65037 100644 --- a/src/modules/Stickers.ts +++ b/src/modules/Stickers.ts @@ -1,34 +1,28 @@ import { LayerGroup, layerGroup, Map } from 'leaflet'; -import { Sticker } from '$modules/Sticker'; +import { IStickerDump, Sticker } from '$modules/Sticker'; import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js'; import { clusterIcon } from '$utils/clusterIcon'; import { Editor } from "$modules/Editor"; -interface IStickers { - clusterLayer: MarkerClusterGroup; - map: Map; - stickers: Array; - layer: LayerGroup; - triggerOnChange: () => void; +export interface ILatLng { + lat: number, + lng: number, +} + +interface Props { editor: Editor; + map: Map; + triggerOnChange: () => void; lockMapClicks: (x: boolean) => void; } -export class Stickers implements IStickers { - constructor({ map, lockMapClicks, triggerOnChange, editor }) { +export class Stickers { + constructor({ map, lockMapClicks, triggerOnChange, editor }: Props) { this.map = map; this.triggerOnChange = triggerOnChange; this.editor = editor; - this.clusterLayer = new MarkerClusterGroup({ - spiderfyOnMaxZoom: false, - showCoverageOnHover: false, - zoomToBoundsOnClick: true, - animate: false, - maxClusterRadius: 80, - disableClusteringAtZoom: 13, - iconCreateFunction: clusterIcon, - }).addTo(map); + this.clusterLayer.addTo(map); this.clusterLayer.on('animationend', this.onSpiderify); @@ -40,7 +34,7 @@ export class Stickers implements IStickers { createSticker = ({ latlng, sticker, angle = 2.2, text = '', set - }) => { + }: IStickerDump): void => { const marker = new Sticker({ latlng, angle, @@ -58,10 +52,9 @@ export class Stickers implements IStickers { marker.marker.addTo(this.clusterLayer); this.triggerOnChange(); - // marker.marker.enableEdit(); }; - deleteStickerByReference = ref => { + deleteStickerByReference = (ref: Sticker): void => { const index = this.stickers.indexOf(ref); if (index < 0) return; @@ -72,7 +65,7 @@ export class Stickers implements IStickers { this.triggerOnChange(); }; - clearAll = () => { + clearAll = (): void => { const target = [...this.stickers]; target.map(sticker => { this.deleteStickerByReference(sticker); @@ -80,9 +73,9 @@ export class Stickers implements IStickers { }); }; - dumpData = () => this.stickers.map(sticker => sticker.dumpData()); + dumpData = (): Array => this.stickers.map(sticker => sticker.dumpData()); - onSpiderify = () => { + onSpiderify = (): void => { // todo: it has markers passed as argument. Update only them. if (this.editor.getEditing()) { this.startEditing(); @@ -91,20 +84,31 @@ export class Stickers implements IStickers { } }; - startEditing = () => { + startEditing = (): void => { this.stickers.map(sticker => sticker.startEditing()); }; - stopEditing = () => { + stopEditing = (): void => { this.stickers.map(sticker => sticker.stopEditing()); }; - clusterLayer; - map; - stickers; - triggerOnChange; - editor; - lockMapClicks; + clusterLayer: MarkerClusterGroup = new MarkerClusterGroup({ + spiderfyOnMaxZoom: false, + showCoverageOnHover: false, + zoomToBoundsOnClick: true, + animate: false, + maxClusterRadius: 80, + disableClusteringAtZoom: 13, + iconCreateFunction: clusterIcon, + }); - layer = layerGroup(); + editor: Props['editor']; + map: Props['map']; + + + stickers: Array = []; + layer: LayerGroup = layerGroup(); + + triggerOnChange: Props['triggerOnChange']; + lockMapClicks: Props['lockMapClicks']; }