mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 11:06:40 +07:00
drawing arrows
This commit is contained in:
parent
f8d16d150a
commit
3f2e2ba856
7 changed files with 65 additions and 14 deletions
|
@ -76,7 +76,6 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
|
||||||
});
|
});
|
||||||
|
|
||||||
stopEditing = (): void => {
|
stopEditing = (): void => {
|
||||||
console.log('stop it!');
|
|
||||||
this.setState({ editor_target: null });
|
this.setState({ editor_target: null });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,6 @@
|
||||||
todo polyline editing only in manual mode (or by click)
|
todo polyline editing only in manual mode (or by click)
|
||||||
todo selecting logo on crop
|
todo selecting logo on crop
|
||||||
|
|
||||||
done public maps
|
|
||||||
done editing map on map list
|
|
||||||
done setting map public on map list
|
|
||||||
|
|
||||||
todo network operations notify
|
todo network operations notify
|
||||||
done delayed notify (delay(2000).then(showLoadingMsg))
|
done delayed notify (delay(2000).then(showLoadingMsg))
|
||||||
todo network error notifications
|
todo network error notifications
|
||||||
|
@ -28,6 +24,10 @@
|
||||||
|
|
||||||
## DONE
|
## DONE
|
||||||
|
|
||||||
|
done public maps
|
||||||
|
done editing map on map list
|
||||||
|
done setting map public on map list
|
||||||
|
|
||||||
done routing spinner
|
done routing spinner
|
||||||
done maybe: stickers clusterization?
|
done maybe: stickers clusterization?
|
||||||
done moving out the screen makes stickers editable again
|
done moving out the screen makes stickers editable again
|
||||||
|
|
|
@ -41,6 +41,7 @@ import { MODES } from '$constants/modes';
|
||||||
import { DEFAULT_USER } from '$constants/auth';
|
import { DEFAULT_USER } from '$constants/auth';
|
||||||
import { TIPS } from '$constants/tips';
|
import { TIPS } from '$constants/tips';
|
||||||
import {
|
import {
|
||||||
|
composeArrows,
|
||||||
composeImages,
|
composeImages,
|
||||||
composePoly, composeStickers, downloadCanvas,
|
composePoly, composeStickers, downloadCanvas,
|
||||||
fetchImages,
|
fetchImages,
|
||||||
|
@ -362,6 +363,7 @@ function* getRenderData() {
|
||||||
|
|
||||||
yield composeImages({ geometry, images, ctx });
|
yield composeImages({ geometry, images, ctx });
|
||||||
yield composePoly({ points, ctx });
|
yield composePoly({ points, ctx });
|
||||||
|
yield composeArrows({ points, ctx });
|
||||||
yield composeStickers({ stickers, ctx });
|
yield composeStickers({ stickers, ctx });
|
||||||
|
|
||||||
yield put(setRenderer({ info: 'Готово', progress: 1 }));
|
yield put(setRenderer({ info: 'Готово', progress: 1 }));
|
||||||
|
|
5
src/sprites/arrow.svg
Normal file
5
src/sprites/arrow.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="48" height="48" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="path-arrow" transform="scale(2) translate(5 -2)">
|
||||||
|
<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>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 297 B |
|
@ -1,5 +1,8 @@
|
||||||
import { divIcon, LatLngLiteral, Marker, marker, DivIcon } from "leaflet";
|
import { divIcon, LatLngLiteral, Marker, marker, DivIcon } from "leaflet";
|
||||||
|
|
||||||
|
const arrow_image = require('$sprites/arrow.svg');
|
||||||
|
|
||||||
|
// <use xlink:href="#path-arrow" transform="scale(2) translate(5 -2)"/>
|
||||||
export const createArrow = (latlng: LatLngLiteral, angle: number): Marker => marker(latlng, {
|
export const createArrow = (latlng: LatLngLiteral, angle: number): Marker => marker(latlng, {
|
||||||
draggable: false,
|
draggable: false,
|
||||||
interactive: false,
|
interactive: false,
|
||||||
|
@ -7,7 +10,7 @@ export const createArrow = (latlng: LatLngLiteral, angle: number): Marker => mar
|
||||||
html: `
|
html: `
|
||||||
<div class="leaflet-arrow" style="transform: rotate(${angle}deg);">
|
<div class="leaflet-arrow" style="transform: rotate(${angle}deg);">
|
||||||
<svg width="48" height="48" preserveAspectRatio="xMidYMid">
|
<svg width="48" height="48" preserveAspectRatio="xMidYMid">
|
||||||
<use xlink:href="#path-arrow" transform="scale(2) translate(5 -2)"/>
|
<image xlink:href="${arrow_image}" x="0" y="0" width="48" height="48"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { LatLng, LatLngLiteral, Point, PointExpression } from "leaflet";
|
import { LatLng, LatLngLiteral, point, Point, PointExpression } from "leaflet";
|
||||||
|
|
||||||
interface ILatLng {
|
interface ILatLng {
|
||||||
lat: number,
|
lat: number,
|
||||||
|
@ -10,9 +10,18 @@ export const middleCoord = (l1: ILatLng, l2: ILatLng): ILatLng => ({
|
||||||
lng: (l2.lng + ((l1.lng - l2.lng) / 2))
|
lng: (l2.lng + ((l1.lng - l2.lng) / 2))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const middleCoordPx = (p1: Point, p2: Point): Point => point({
|
||||||
|
x: (p1.x + ((p2.x - p1.x) / 2)),
|
||||||
|
y: (p1.y + ((p2.y - p1.y) / 2))
|
||||||
|
});
|
||||||
|
|
||||||
export const deg2rad = (deg: number): number => ((deg * Math.PI) / 180);
|
export const deg2rad = (deg: number): number => ((deg * Math.PI) / 180);
|
||||||
export const rad2deg = (rad: number): number => ((rad / Math.PI) * 180);
|
export const rad2deg = (rad: number): number => ((rad / Math.PI) * 180);
|
||||||
|
|
||||||
|
export const findDistancePx = (p1: Point, p2: Point): number => {
|
||||||
|
return Math.sqrt(((p1.x - p2.x) ** 2) + ((p1.y - p2.y) ** 2));
|
||||||
|
};
|
||||||
|
|
||||||
export const findDistance = (t1: number, n1: number, t2: number, n2: number): number => {
|
export const findDistance = (t1: number, n1: number, t2: number, n2: number): number => {
|
||||||
// convert coordinates to radians
|
// convert coordinates to radians
|
||||||
const lat1 = deg2rad(t1);
|
const lat1 = deg2rad(t1);
|
||||||
|
|
|
@ -6,11 +6,8 @@ import { STICKERS } from '$constants/stickers';
|
||||||
import { ILatLng } from "$modules/Stickers";
|
import { ILatLng } from "$modules/Stickers";
|
||||||
import { IStickerDump } from "$modules/Sticker";
|
import { IStickerDump } from "$modules/Sticker";
|
||||||
import { IRootState } from "$redux/user/reducer";
|
import { IRootState } from "$redux/user/reducer";
|
||||||
|
import { angleBetweenPoints, angleBetweenPointsRad, findDistancePx, middleCoordPx } from "$utils/geom";
|
||||||
export interface IMapPoint {
|
import { Point } from "leaflet";
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ITilePlacement {
|
export interface ITilePlacement {
|
||||||
minX: number,
|
minX: number,
|
||||||
|
@ -86,7 +83,7 @@ export const getTilePlacement = (): ITilePlacement => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPolyPlacement = (): IMapPoint[] => (
|
export const getPolyPlacement = (): Point[] => (
|
||||||
(!editor.poly.poly || !editor.poly.poly.getLatLngs() || editor.poly.poly.getLatLngs().length <= 0)
|
(!editor.poly.poly || !editor.poly.poly.getLatLngs() || editor.poly.poly.getLatLngs().length <= 0)
|
||||||
? []
|
? []
|
||||||
: editor.poly.poly.getLatLngs().map((latlng) => ({ ...editor.map.map.latLngToContainerPoint(latlng) }))
|
: editor.poly.poly.getLatLngs().map((latlng) => ({ ...editor.map.map.latLngToContainerPoint(latlng) }))
|
||||||
|
@ -148,7 +145,7 @@ export const composeImages = (
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const composePoly = ({ points, ctx }: { points: IMapPoint[], ctx: CanvasRenderingContext2D }): void => {
|
export const composePoly = ({ points, ctx }: { points: Point[], ctx: CanvasRenderingContext2D }): void => {
|
||||||
if (editor.poly.isEmpty) return;
|
if (editor.poly.isEmpty) return;
|
||||||
|
|
||||||
let minX = points[0].x;
|
let minX = points[0].x;
|
||||||
|
@ -183,6 +180,42 @@ export const composePoly = ({ points, ctx }: { points: IMapPoint[], ctx: CanvasR
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const composeArrows = async ({ points, ctx }: { points: Point[], ctx: CanvasRenderingContext2D }): Promise<boolean[]> => {
|
||||||
|
const image = await imageFetcher(require('$sprites/arrow.svg'));
|
||||||
|
|
||||||
|
const distances = points.map((point, i) => (
|
||||||
|
(points[i + 1] && findDistancePx(points[i], points[i + 1])) || 0
|
||||||
|
));
|
||||||
|
|
||||||
|
// we want to annotate at least 5 arrows
|
||||||
|
const min_arrows = (distances.length >= 5 ? 5 : distances.length - 1);
|
||||||
|
const min_distance = distances.sort((a, b) => (b - a))[min_arrows];
|
||||||
|
|
||||||
|
return points.map((point, i) => {
|
||||||
|
if (!points[i + 1]) return false;
|
||||||
|
|
||||||
|
const distance = findDistancePx(points[i], points[i + 1]);
|
||||||
|
const angle = angleBetweenPointsRad(points[i], points[i + 1]);
|
||||||
|
|
||||||
|
if (distance < min_distance && distance < 100) return false;
|
||||||
|
|
||||||
|
const middle = middleCoordPx(points[i], points[i + 1]);
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(middle.x, middle.y);
|
||||||
|
ctx.rotate((Math.PI * 0.5) - angle);
|
||||||
|
ctx.translate(-middle.x, -middle.y);
|
||||||
|
|
||||||
|
ctx.moveTo(middle.x, middle.y);
|
||||||
|
|
||||||
|
ctx.drawImage(image, middle.x - 24, middle.y - 24, 48, 48);
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const measureText = (
|
const measureText = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
text: string,
|
text: string,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue