diff --git a/src/components/panels/DistanceBar.tsx b/src/components/panels/DistanceBar.tsx index 5ea8699..dd4df1e 100644 --- a/src/components/panels/DistanceBar.tsx +++ b/src/components/panels/DistanceBar.tsx @@ -57,7 +57,7 @@ class Component extends React.PureComponent { - {toHours(estimated)} +
{toHours(estimated)}
{ dialogOpened && diff --git a/src/modules/InteractivePoly.ts b/src/modules/InteractivePoly.ts index 4ac24cc..cb2f819 100644 --- a/src/modules/InteractivePoly.ts +++ b/src/modules/InteractivePoly.ts @@ -33,8 +33,8 @@ export class Component extends Polyline { this.constraintsStyle = { ...this.constraintsStyle, ...options.constraintsStyle }; this.maxMarkers = options.maxMarkers || this.maxMarkers; - this.kmMarksEnabled = options.kmMarksEnabled || this.kmMarksEnabled; - this.kmMarksStep = options.kmMarksStep || this.kmMarksStep; + // this.kmMarksEnabled = options.kmMarksEnabled || this.kmMarksEnabled; + // this.kmMarksStep = options.kmMarksStep || this.kmMarksStep; this.constrLine = new Polyline([], this.constraintsStyle); @@ -49,7 +49,7 @@ export class Component extends Polyline { this.setLatLngs(latlngs); this.recreateMarkers(); this.recalcDistance(); - this.recalcKmMarks(); + // this.recalcKmMarks(); this.touchHinter.setLatLngs(latlngs); this.fire('latlngschange', { latlngs }); }; @@ -483,35 +483,35 @@ export class Component extends Polyline { this.fire('distancechange', { distance: this.distance }); }; + // + // recalcKmMarks = () => { + // if (!this.kmMarksEnabled) return; + // + // const latlngs = this.getLatLngs() as LatLngLiteral[]; + // + // this.kmMarks = { }; + // + // let last_km_mark = 0; + // + // latlngs.reduce((dist, latlng, index) => { + // if (index >= latlngs.length - 1) return; + // + // const next = latlngs[index + 1]; + // const sum = dist + distKm(latlng, next); + // const rounded = Math.floor(dist / this.kmMarksStep) * this.kmMarksStep; + // + // if (rounded > last_km_mark) { + // last_km_mark = rounded; + // this.kmMarks[rounded] = latlng; + // } + // + // return sum; + // }, 0); + // }; - recalcKmMarks = () => { - if (!this.kmMarksEnabled) return; - - const latlngs = this.getLatLngs() as LatLngLiteral[]; - - this.kmMarks = { }; - - let last_km_mark = 0; - - latlngs.reduce((dist, latlng, index) => { - if (index >= latlngs.length - 1) return; - - const next = latlngs[index + 1]; - const sum = dist + distKm(latlng, next); - const rounded = Math.floor(dist / this.kmMarksStep) * this.kmMarksStep; - - if (rounded > last_km_mark) { - last_km_mark = rounded; - this.kmMarks[rounded] = latlng; - } - - return sum; - }, 0); - }; - - kmMarksEnabled?: InteractivePolylineOptions['kmMarksEnabled'] = true; - kmMarksStep?: InteractivePolylineOptions['kmMarksStep'] = 5; - kmMarks?: { [x: number]: LatLngLiteral }; + // kmMarksEnabled?: InteractivePolylineOptions['kmMarksEnabled'] = true; + // kmMarksStep?: InteractivePolylineOptions['kmMarksStep'] = 5; + // kmMarks?: { [x: number]: LatLngLiteral }; // kmMarksLayer?: LayerGroup = new LayerGroup(); markers: Marker[] = []; diff --git a/src/modules/KmMarks.ts b/src/modules/KmMarks.ts new file mode 100644 index 0000000..554087c --- /dev/null +++ b/src/modules/KmMarks.ts @@ -0,0 +1,127 @@ +import { divIcon, LatLngLiteral, LayerGroup, Map, marker, Marker } from "leaflet"; +import { arrowClusterIcon, createArrow } from "$utils/arrow"; +import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js'; +import { angleBetweenPoints, dist2, distKm, middleCoord } from "$utils/geom"; + +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: 5, + ...(options || {}), + } as KmMarksOptions; + } + + setLatLngs = (latlngs: LatLngLiteral[]): void => { + if (!this.map) return; + this.marksLayer.clearLayers(); + + if (latlngs.length === 0) 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; + + latlngs.reduce((dist, current, index) => { + if (index >= latlngs.length - 1) return; + + 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), + ); + + console.log(`[${count}] found at ${index}`, dist, sum, rounded); + + 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)); + + console.log('-->', step, shift); + } + + last_km_mark = rounded; + } + + return sum; + }, 0); + + console.log(kmMarks); + }; + + 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] + }) + }); + + + drawEndMarker = (latlngs: LatLngLiteral[]): void => { + + }; + + options: KmMarksOptions; + map: Map; + marksLayer: MarkerClusterGroup = new MarkerClusterGroup({ + spiderfyOnMaxZoom: false, + showCoverageOnHover: false, + zoomToBoundsOnClick: false, + animate: false, + maxClusterRadius: 10, + // iconCreateFunction: arrowClusterIcon, + }); +} + + +Component.addInitHook(function () { + this.once('add', (event) => { + if (event.target instanceof KmMarks) { + this.map = event.target._map; + this.marksLayer.addTo(this.map); + } + }); + + this.once('remove', (event) => { + if (event.target instanceof KmMarks) { + this.marksLayer.removeFrom(this.map); + } + }); +}); + +export const KmMarks = Component; diff --git a/src/modules/Poly.ts b/src/modules/Poly.ts index 0c84203..b69e378 100644 --- a/src/modules/Poly.ts +++ b/src/modules/Poly.ts @@ -5,6 +5,7 @@ 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"; interface Props { map: Map; @@ -28,7 +29,7 @@ export class Poly { .on('distancechange', this.onDistanceUpdate) .on('allvertexhide', this.onVertexHide) .on('allvertexshow', this.onVertexShow) - .on('latlngschange', this.updateArrows); + .on('latlngschange', this.updateMarks) this.poly.addTo(map); this.editor = editor; @@ -41,6 +42,7 @@ export class Poly { this.lockMapClicks = lockMapClicks; this.arrows = new Arrows({}).addTo(map); + this.kmMarks = new KmMarks().addTo(map); } onDistanceUpdate = (event) => { @@ -51,11 +53,12 @@ export class Poly { onVertexHide = (): void => this.editor.setMarkersShown(false); onVertexShow = (): void => this.editor.setMarkersShown(true); - updateArrows = event => { + updateMarks = event => { this.editor.setChanged(true); const { latlngs } = event; this.arrows.setLatLngs(latlngs); + this.kmMarks.setLatLngs(latlngs); }; continue = (): void => { @@ -104,6 +107,7 @@ export class Poly { arrows; poly; + kmMarks; editor: Props['editor']; map: Props['map']; diff --git a/src/styles/map.less b/src/styles/map.less index 23cfc4a..97be0a2 100644 --- a/src/styles/map.less +++ b/src/styles/map.less @@ -99,6 +99,27 @@ height: 48px; } +.leaflet-km-marker { + position: relative; + background: green; + + .leaflet-km-dist { + background: blue; + color: white; + border-radius: 11px; + font-size: 9px; + text-align: center; + min-width: 20px; + height: 12px; + display: flex; + align-items: center; + justify-content: center; + position: relative; + top: -5px; + left: -5px; + } +} + .touch-hinter-poly { stroke: rgba(255, 50, 0, 0.1); cursor: grab;