mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 19:16:41 +07:00
added arrows
This commit is contained in:
parent
dfb4d3b98f
commit
968c871c11
6 changed files with 83 additions and 7 deletions
|
@ -38,6 +38,10 @@ export const Fills = () => (
|
||||||
>
|
>
|
||||||
<path d="m 2.625,3.375 h 7.5 L 10.28125,1.609375 13.5,4.25 10.484375,6.921875 10.171875,5.15625 2.625,5.125 Z" fill="#ff3344" fillRule="evenodd" />
|
<path d="m 2.625,3.375 h 7.5 L 10.28125,1.609375 13.5,4.25 10.484375,6.921875 10.171875,5.15625 2.625,5.125 Z" fill="#ff3344" fillRule="evenodd" />
|
||||||
</marker>
|
</marker>
|
||||||
|
|
||||||
|
<g id="path-arrow">
|
||||||
|
<path d="m 2.625,3.375 h 7.5 L 10.28125,1.609375 13.5,4.25 10.484375,6.921875 10.171875,5.15625 2.625,5.125 Z" fill="#ff3344" fillRule="evenodd" />
|
||||||
|
</g>
|
||||||
</defs>
|
</defs>
|
||||||
<image xlinkHref={require('$sprites/stickers/stickers-base.svg')} width={0} height={0} />
|
<image xlinkHref={require('$sprites/stickers/stickers-base.svg')} width={0} height={0} />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -595,4 +595,6 @@ export const InteractivePoly = Component;
|
||||||
editorenable
|
editorenable
|
||||||
|
|
||||||
distancechange
|
distancechange
|
||||||
|
|
||||||
|
latlngschange
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import { Map, LayerGroup, LatLng } from 'leaflet';
|
import { Map, LayerGroup, LatLng, LatLngLiteral, LeafletEventHandlerFn, marker, divIcon, Marker } from 'leaflet';
|
||||||
import { EditablePolyline } from '$utils/EditablePolyline';
|
import { EditablePolyline } from '$utils/EditablePolyline';
|
||||||
import { simplify } from '$utils/simplify';
|
import { simplify } from '$utils/simplify';
|
||||||
import { CLIENT } from '$config/frontend';
|
import { CLIENT } from '$config/frontend';
|
||||||
import { editor, Editor } from "$modules/Editor";
|
import { editor, Editor } from "$modules/Editor";
|
||||||
import { ILatLng } from "$modules/Stickers";
|
import { ILatLng } from "$modules/Stickers";
|
||||||
import { InteractivePoly } from "$modules/InteractivePoly";
|
import { InteractivePoly } from "$modules/InteractivePoly";
|
||||||
|
import { clusterIcon } from "$utils/clusterIcon";
|
||||||
|
import { MarkerClusterGroup } from 'leaflet.markercluster/dist/leaflet.markercluster-src.js';
|
||||||
|
import { angleBetweenPoints, dist2, distToSegment, middleCoord } from "$utils/geom";
|
||||||
|
import { arrowClusterIcon, createArrow } from "$utils/arrow";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
map: Map;
|
map: Map;
|
||||||
|
@ -29,7 +32,8 @@ export class Poly {
|
||||||
})
|
})
|
||||||
.on('distancechange', this.onDistanceUpdate)
|
.on('distancechange', this.onDistanceUpdate)
|
||||||
.on('allvertexhide', this.onVertexHide)
|
.on('allvertexhide', this.onVertexHide)
|
||||||
.on('allvertexshow', this.onVertexShow);
|
.on('allvertexshow', this.onVertexShow)
|
||||||
|
.on('latlngschange', this.updateArrows);
|
||||||
|
|
||||||
this.poly.addTo(map);
|
this.poly.addTo(map);
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
|
@ -41,7 +45,7 @@ export class Poly {
|
||||||
this.triggerOnChange = triggerOnChange;
|
this.triggerOnChange = triggerOnChange;
|
||||||
this.lockMapClicks = lockMapClicks;
|
this.lockMapClicks = lockMapClicks;
|
||||||
|
|
||||||
this.arrows.addTo(map);
|
this.arrowLayer.addTo(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
onDistanceUpdate = (event) => {
|
onDistanceUpdate = (event) => {
|
||||||
|
@ -52,6 +56,32 @@ export class Poly {
|
||||||
onVertexHide = (): void => this.editor.setMarkersShown(false);
|
onVertexHide = (): void => this.editor.setMarkersShown(false);
|
||||||
onVertexShow = (): void => this.editor.setMarkersShown(true);
|
onVertexShow = (): void => this.editor.setMarkersShown(true);
|
||||||
|
|
||||||
|
updateArrows = event => {
|
||||||
|
const { latlngs } = event;
|
||||||
|
this.arrowLayer.clearLayers();
|
||||||
|
|
||||||
|
if (latlngs.length === 0) return;
|
||||||
|
|
||||||
|
const midpoints = latlngs.reduce((res, latlng, i) => (
|
||||||
|
latlngs[i + 1] && dist2(latlngs[i], latlngs[i + 1]) > 0.00005
|
||||||
|
? [
|
||||||
|
...res,
|
||||||
|
{
|
||||||
|
latlng: middleCoord(latlngs[i], latlngs[i + 1]),
|
||||||
|
angle: angleBetweenPoints(
|
||||||
|
this.map.latLngToContainerPoint(latlngs[i]),
|
||||||
|
this.map.latLngToContainerPoint(latlngs[i + 1])
|
||||||
|
),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: res
|
||||||
|
), []);
|
||||||
|
|
||||||
|
midpoints.forEach(({ latlng, angle }) => (
|
||||||
|
this.arrowLayer.addLayer(createArrow(latlng, angle))
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
// setModeOnDrawing = (): void => {
|
// setModeOnDrawing = (): void => {
|
||||||
// if (this.editor.getMode() !== MODES.POLY) this.editor.setMode(MODES.POLY);
|
// if (this.editor.getMode() !== MODES.POLY) this.editor.setMode(MODES.POLY);
|
||||||
// };
|
// };
|
||||||
|
@ -133,7 +163,15 @@ export class Poly {
|
||||||
}
|
}
|
||||||
|
|
||||||
poly: EditablePolyline;
|
poly: EditablePolyline;
|
||||||
arrows: LayerGroup = new LayerGroup();
|
arrowLayer: MarkerClusterGroup = new MarkerClusterGroup({
|
||||||
|
spiderfyOnMaxZoom: false,
|
||||||
|
showCoverageOnHover: false,
|
||||||
|
zoomToBoundsOnClick: false,
|
||||||
|
animate: false,
|
||||||
|
maxClusterRadius: 100,
|
||||||
|
// disableClusteringAtZoom: 13,
|
||||||
|
iconCreateFunction: arrowClusterIcon,
|
||||||
|
});
|
||||||
|
|
||||||
editor: Props['editor'];
|
editor: Props['editor'];
|
||||||
map: Props['map'];
|
map: Props['map'];
|
||||||
|
|
|
@ -91,6 +91,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leaflet-arrow {
|
||||||
|
position: absolute;
|
||||||
|
left: -14px;
|
||||||
|
top: -14px;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.touch-hinter-poly {
|
.touch-hinter-poly {
|
||||||
stroke: rgba(255, 50, 0, 0.1);
|
stroke: rgba(255, 50, 0, 0.1);
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
|
|
22
src/utils/arrow.ts
Normal file
22
src/utils/arrow.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { divIcon, LatLngLiteral, Marker, marker, DivIcon } from "leaflet";
|
||||||
|
|
||||||
|
export const createArrow = (latlng: LatLngLiteral, angle: number): Marker => marker(latlng, {
|
||||||
|
draggable: false,
|
||||||
|
interactive: false,
|
||||||
|
icon: divIcon({
|
||||||
|
html: `
|
||||||
|
<div class="leaflet-arrow" style="transform: rotate(${angle}deg);">
|
||||||
|
<svg width="40" height="40" preserveAspectRatio="xMidYMid">
|
||||||
|
<use xlink:href="#path-arrow" transform="scale(2)"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
className: 'leaflet-arrow-icon',
|
||||||
|
iconSize: [11, 11],
|
||||||
|
iconAnchor: [6, 6]
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
export const arrowClusterIcon = (): DivIcon => divIcon({
|
||||||
|
html: `<div class="leaflet-arrow-cluster"></div>`
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
import { LatLng, LatLngLiteral } from "leaflet";
|
import { LatLng, LatLngLiteral, Point } from "leaflet";
|
||||||
|
|
||||||
interface ILatLng {
|
interface ILatLng {
|
||||||
lat: number,
|
lat: number,
|
||||||
|
@ -58,7 +58,7 @@ export const pointInArea = (A: LatLng, B: LatLng, C: LatLng, radius: number = 0.
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const dist2 = (A: LatLngLiteral, B: LatLngLiteral): number => (((A.lat - B.lat) ** 2) + ((A.lng - B.lng) ** 2));
|
export const dist2 = (A: LatLngLiteral, B: LatLngLiteral): number => (((A.lat - B.lat) ** 2) + ((A.lng - B.lng) ** 2));
|
||||||
|
|
||||||
const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => {
|
const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => {
|
||||||
const l2 = dist2(A, B);
|
const l2 = dist2(A, B);
|
||||||
|
@ -83,3 +83,5 @@ const distToSegmentSquared = (A: LatLng, B: LatLng, C: LatLng): number => {
|
||||||
export const distToSegment = (A: LatLng, B: LatLng, C: LatLng): number => Math.sqrt(distToSegmentSquared(A, B, C));
|
export const distToSegment = (A: LatLng, B: LatLng, C: LatLng): number => Math.sqrt(distToSegmentSquared(A, B, C));
|
||||||
// if C between A and B
|
// if C between A and B
|
||||||
export const pointBetweenPoints = (A: LatLng, B: LatLng, C: LatLng): boolean => (distToSegment(A, B, C) < 0.01);
|
export const pointBetweenPoints = (A: LatLng, B: LatLng, C: LatLng): boolean => (distToSegment(A, B, C) < 0.01);
|
||||||
|
|
||||||
|
export const angleBetweenPoints = (A: Point, B: Point): number => parseFloat(((Math.atan2(B.y - A.y, B.x - A.x))* 180 / Math.PI).toFixed(6));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue