mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 11:06:40 +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" />
|
||||
</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>
|
||||
<image xlinkHref={require('$sprites/stickers/stickers-base.svg')} width={0} height={0} />
|
||||
</svg>
|
||||
|
|
|
@ -595,4 +595,6 @@ export const InteractivePoly = Component;
|
|||
editorenable
|
||||
|
||||
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 { simplify } from '$utils/simplify';
|
||||
import { CLIENT } from '$config/frontend';
|
||||
import { editor, Editor } from "$modules/Editor";
|
||||
import { ILatLng } from "$modules/Stickers";
|
||||
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 {
|
||||
map: Map;
|
||||
|
@ -29,7 +32,8 @@ export class Poly {
|
|||
})
|
||||
.on('distancechange', this.onDistanceUpdate)
|
||||
.on('allvertexhide', this.onVertexHide)
|
||||
.on('allvertexshow', this.onVertexShow);
|
||||
.on('allvertexshow', this.onVertexShow)
|
||||
.on('latlngschange', this.updateArrows);
|
||||
|
||||
this.poly.addTo(map);
|
||||
this.editor = editor;
|
||||
|
@ -41,7 +45,7 @@ export class Poly {
|
|||
this.triggerOnChange = triggerOnChange;
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
|
||||
this.arrows.addTo(map);
|
||||
this.arrowLayer.addTo(map);
|
||||
}
|
||||
|
||||
onDistanceUpdate = (event) => {
|
||||
|
@ -52,6 +56,32 @@ export class Poly {
|
|||
onVertexHide = (): void => this.editor.setMarkersShown(false);
|
||||
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 => {
|
||||
// if (this.editor.getMode() !== MODES.POLY) this.editor.setMode(MODES.POLY);
|
||||
// };
|
||||
|
@ -133,7 +163,15 @@ export class Poly {
|
|||
}
|
||||
|
||||
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'];
|
||||
map: Props['map'];
|
||||
|
|
|
@ -91,6 +91,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.leaflet-arrow {
|
||||
position: absolute;
|
||||
left: -14px;
|
||||
top: -14px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.touch-hinter-poly {
|
||||
stroke: rgba(255, 50, 0, 0.1);
|
||||
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 {
|
||||
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 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));
|
||||
// if C between A and B
|
||||
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