drawing arrows

This commit is contained in:
muerwre 2019-03-07 16:37:40 +07:00
parent f8d16d150a
commit 3f2e2ba856
7 changed files with 65 additions and 14 deletions

View file

@ -76,7 +76,6 @@ class Component extends React.Component<IMapListDialogProps, IMapListDialogState
});
stopEditing = (): void => {
console.log('stop it!');
this.setState({ editor_target: null });
};

View file

@ -14,10 +14,6 @@
todo polyline editing only in manual mode (or by click)
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
done delayed notify (delay(2000).then(showLoadingMsg))
todo network error notifications
@ -28,6 +24,10 @@
## DONE
done public maps
done editing map on map list
done setting map public on map list
done routing spinner
done maybe: stickers clusterization?
done moving out the screen makes stickers editable again

View file

@ -41,6 +41,7 @@ import { MODES } from '$constants/modes';
import { DEFAULT_USER } from '$constants/auth';
import { TIPS } from '$constants/tips';
import {
composeArrows,
composeImages,
composePoly, composeStickers, downloadCanvas,
fetchImages,
@ -362,6 +363,7 @@ function* getRenderData() {
yield composeImages({ geometry, images, ctx });
yield composePoly({ points, ctx });
yield composeArrows({ points, ctx });
yield composeStickers({ stickers, ctx });
yield put(setRenderer({ info: 'Готово', progress: 1 }));

5
src/sprites/arrow.svg Normal file
View 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

View file

@ -1,5 +1,8 @@
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, {
draggable: false,
interactive: false,
@ -7,7 +10,7 @@ export const createArrow = (latlng: LatLngLiteral, angle: number): Marker => mar
html: `
<div class="leaflet-arrow" style="transform: rotate(${angle}deg);">
<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>
</div>
`,

View file

@ -1,4 +1,4 @@
import { LatLng, LatLngLiteral, Point, PointExpression } from "leaflet";
import { LatLng, LatLngLiteral, point, Point, PointExpression } from "leaflet";
interface ILatLng {
lat: number,
@ -10,9 +10,18 @@ export const middleCoord = (l1: ILatLng, l2: ILatLng): ILatLng => ({
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 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 => {
// convert coordinates to radians
const lat1 = deg2rad(t1);

View file

@ -6,11 +6,8 @@ import { STICKERS } from '$constants/stickers';
import { ILatLng } from "$modules/Stickers";
import { IStickerDump } from "$modules/Sticker";
import { IRootState } from "$redux/user/reducer";
export interface IMapPoint {
x: number,
y: number,
}
import { angleBetweenPoints, angleBetweenPointsRad, findDistancePx, middleCoordPx } from "$utils/geom";
import { Point } from "leaflet";
export interface ITilePlacement {
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.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;
let minX = points[0].x;
@ -183,6 +180,42 @@ export const composePoly = ({ points, ctx }: { points: IMapPoint[], ctx: CanvasR
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 = (
ctx: CanvasRenderingContext2D,
text: string,