mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 02:56:41 +07:00
stickers: drawing arrow + text
This commit is contained in:
parent
f183c8593d
commit
9729a9e117
11 changed files with 120 additions and 25 deletions
|
@ -14,3 +14,5 @@ const database = mongoose.connection;
|
|||
|
||||
database.on('error', (err) => { console.error(`Database Connection Error: ${err}`); process.exit(2); });
|
||||
database.on('connected', () => { console.info('Succesfully connected to MongoDB Database'); });
|
||||
|
||||
console.log(`DB: mongodb://${USER}:${PASSWORD}@${HOSTNAME}:${PORT}/${DATABASE}`);
|
||||
|
|
|
@ -8,8 +8,8 @@ const RouteSchema = new Schema(
|
|||
title: { type: String, default: '' },
|
||||
// address: { type: String, required: true },
|
||||
version: { type: Number, default: 2 },
|
||||
route: { type: Array },
|
||||
stickers: { type: Array },
|
||||
route: { type: Array, default: [] },
|
||||
stickers: { type: Array, default: [] },
|
||||
owner: { type: Schema.Types.ObjectId, ref: 'User' },
|
||||
logo: { type: String, default: 'DEFAULT' },
|
||||
distance: { type: Number, default: 0 },
|
||||
|
|
|
@ -8,7 +8,7 @@ module.exports = async (req, res) => {
|
|||
path: 'routes',
|
||||
options: {
|
||||
limit: 100,
|
||||
sort: { updated: 1 },
|
||||
sort: { updated_at: -1 },
|
||||
}
|
||||
});
|
||||
const random_url = await generateRandomUrl();
|
||||
|
|
|
@ -9,7 +9,7 @@ module.exports.parseRoute = route => route.filter(el => (
|
|||
));
|
||||
|
||||
module.exports.parseStickers = stickers => stickers.filter(el => (
|
||||
Object.keys(el).length === 4
|
||||
Object.keys(el).length === 5
|
||||
&& el.latlng
|
||||
&& Object.keys(el.latlng).length === 2
|
||||
&& el.latlng.lat
|
||||
|
|
|
@ -30,7 +30,7 @@ export const RouteRow = ({
|
|||
<div className="route-description">
|
||||
<span>
|
||||
<Icon icon="icon-cycle-1" />
|
||||
{(distance && `${distance} km`) || 'N/A'}
|
||||
{(distance && `${distance} km`) || '0 km'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
setTitle,
|
||||
} from '$redux/user/actions';
|
||||
import { DEFAULT_PROVIDER, PROVIDERS } from '$constants/providers';
|
||||
import { STICKERS } from '$constants/stickers';
|
||||
|
||||
export class Editor {
|
||||
constructor() {
|
||||
|
@ -136,7 +137,7 @@ export class Editor {
|
|||
if (!e || !e.latlng || !this.activeSticker) return;
|
||||
const { latlng } = e;
|
||||
|
||||
this.stickers.createSticker({ latlng, sticker: this.activeSticker });
|
||||
this.stickers.createSticker({ latlng, sticker: this.activeSticker.sticker, set: this.activeSticker.set });
|
||||
this.setActiveSticker(null);
|
||||
this.setChanged(true);
|
||||
};
|
||||
|
@ -232,12 +233,18 @@ export class Editor {
|
|||
|
||||
this.stickers.clearAll();
|
||||
if (stickers) {
|
||||
stickers.map(sticker => this.stickers.createSticker({
|
||||
latlng: sticker.latlng,
|
||||
angle: parseStickerAngle({ sticker, version }),
|
||||
sticker: parseStickerStyle({ sticker, version }),
|
||||
text: sticker.text,
|
||||
}));
|
||||
stickers.map(sticker =>
|
||||
sticker.set && STICKERS[sticker.set].url &&
|
||||
this.stickers.createSticker({
|
||||
latlng: sticker.latlng,
|
||||
// angle: parseStickerAngle({ sticker, version }),
|
||||
// sticker: parseStickerStyle({ sticker, version }),
|
||||
angle: sticker.angle,
|
||||
sticker: sticker.sticker,
|
||||
set: sticker.set,
|
||||
text: sticker.text,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (owner) this.owner = owner;
|
||||
|
|
|
@ -10,7 +10,7 @@ import classnames from 'classnames';
|
|||
|
||||
export class Sticker {
|
||||
constructor({
|
||||
latlng, deleteSticker, map, lockMapClicks, sticker, triggerOnChange, angle = 2.2, text = '',
|
||||
latlng, deleteSticker, map, lockMapClicks, sticker, set, triggerOnChange, angle = 2.2, text = '',
|
||||
}) {
|
||||
this.text = text;
|
||||
this.latlng = latlng;
|
||||
|
@ -18,6 +18,7 @@ export class Sticker {
|
|||
this.isDragging = false;
|
||||
this.map = map;
|
||||
this.sticker = sticker;
|
||||
this.set = set;
|
||||
this.editable = true;
|
||||
this.triggerOnChange = triggerOnChange;
|
||||
this.direction = 'right';
|
||||
|
@ -38,7 +39,7 @@ export class Sticker {
|
|||
onMouseUp={this.onDragStop}
|
||||
>
|
||||
<StickerDesc value={this.text} onChange={this.setText} />
|
||||
{this.generateStickerSVG(sticker)}
|
||||
{this.generateStickerSVG(set, sticker)}
|
||||
<div
|
||||
className="sticker-delete"
|
||||
onMouseDown={this.onDelete}
|
||||
|
@ -163,20 +164,23 @@ export class Sticker {
|
|||
this.stickerArrow.style.transform = `rotate(${angle + Math.PI}rad)`;
|
||||
};
|
||||
|
||||
generateStickerSVG = ({ set, sticker }) => (
|
||||
<div
|
||||
className="sticker-image"
|
||||
style={{
|
||||
generateStickerSVG = (set, sticker) => {
|
||||
return (
|
||||
<div
|
||||
className="sticker-image"
|
||||
style={{
|
||||
backgroundImage: `url('${STICKERS[set].url}`,
|
||||
backgroundPosition: `${-STICKERS[set].layers[sticker].off * 72} 50%`,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
dumpData = () => ({
|
||||
angle: this.angle,
|
||||
latlng: { ...this.marker.getLatLng() },
|
||||
sticker: this.sticker,
|
||||
set: this.set,
|
||||
text: this.text,
|
||||
});
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ export class Stickers {
|
|||
// this.createSticker({ latlng });
|
||||
// };
|
||||
|
||||
createSticker = ({ latlng, sticker, angle = 2.2, text = '' }) => {
|
||||
createSticker = ({ latlng, sticker, angle = 2.2, text = '', set }) => {
|
||||
const marker = new Sticker({
|
||||
latlng,
|
||||
angle,
|
||||
|
@ -28,6 +28,7 @@ export class Stickers {
|
|||
map: this.map,
|
||||
lockMapClicks: this.lockMapClicks,
|
||||
sticker,
|
||||
set,
|
||||
triggerOnChange: this.triggerOnChange,
|
||||
text,
|
||||
});
|
||||
|
|
|
@ -20,9 +20,9 @@ import { DEFAULT_USER } from '$constants/auth';
|
|||
import { TIPS } from '$constants/tips';
|
||||
import {
|
||||
composeImages,
|
||||
composePoly, downloadCanvas,
|
||||
composePoly, composeStickers, downloadCanvas,
|
||||
fetchImages,
|
||||
getPolyPlacement,
|
||||
getPolyPlacement, getStickersPlacement,
|
||||
getTilePlacement,
|
||||
imageFetcher
|
||||
} from '$utils/renderer';
|
||||
|
@ -259,12 +259,15 @@ function* getRenderData() {
|
|||
|
||||
const geometry = getTilePlacement();
|
||||
const points = getPolyPlacement();
|
||||
const stickers = getStickersPlacement();
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const images = yield fetchImages(ctx, geometry);
|
||||
|
||||
yield composeImages({ geometry, images, ctx });
|
||||
yield composePoly({ points, ctx });
|
||||
yield composeStickers({ stickers, ctx });
|
||||
|
||||
return yield canvas.toDataURL('image/jpeg');
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
|
||||
.sticker-desc {
|
||||
min-width: 60px;
|
||||
|
||||
z-index: -1;
|
||||
height: auto;
|
||||
background: #222222;
|
||||
position: absolute;
|
||||
|
|
|
@ -65,6 +65,17 @@ export const getPolyPlacement = () => (
|
|||
: editor.poly.poly.getLatLngs().map((latlng) => ({ ...editor.map.map.latLngToContainerPoint(latlng) }))
|
||||
);
|
||||
|
||||
export const getStickersPlacement = () => (
|
||||
(!editor.stickers || editor.stickers.dumpData().length <= 0)
|
||||
? []
|
||||
: editor.stickers.dumpData().map(({ latlng: { lat, lng }, text, angle, sticker }) => ({
|
||||
...editor.map.map.latLngToContainerPoint({ lat, lng }),
|
||||
text,
|
||||
sticker,
|
||||
angle,
|
||||
}))
|
||||
);
|
||||
|
||||
const getImageSource = coords => replaceProviderUrl(editor.provider, coords);
|
||||
|
||||
export const imageFetcher = source => new Promise((resolve, reject) => {
|
||||
|
@ -142,7 +153,74 @@ export const composePoly = ({ points, ctx }) => {
|
|||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
|
||||
return true;
|
||||
return;
|
||||
};
|
||||
|
||||
const measureText = (ctx, text, lineHeight) => (
|
||||
text.split('\n').reduce((obj, line) => (
|
||||
{
|
||||
width: Math.max(ctx.measureText(line).width, obj.width),
|
||||
height: obj.height + lineHeight,
|
||||
}
|
||||
), { width: 0, height: 0 })
|
||||
);
|
||||
|
||||
const composeStickerArrow = (ctx, x, y, angle) => {
|
||||
ctx.save();
|
||||
ctx.translate(x, y);
|
||||
ctx.rotate(angle + (Math.PI * 0.75));
|
||||
ctx.translate(-x, -y);
|
||||
ctx.fillStyle = 'red';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x + 38, y + 20);
|
||||
ctx.lineTo(x + 38, y + 38);
|
||||
ctx.lineTo(x + 20, y + 38);
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
const composeStickerText = (ctx, x, y, angle, text) => {
|
||||
const rad = 56;
|
||||
const tX = ((Math.cos(angle + Math.PI) * rad) - 30) + x + 28;
|
||||
const tY = ((Math.sin(angle + Math.PI) * rad) - 30) + y + 29;
|
||||
|
||||
ctx.font = '12px "Helvetica Neue", Arial';
|
||||
const lines = text.split('\n');
|
||||
const { width, height } = measureText(ctx, text, 16);
|
||||
|
||||
// rectangle
|
||||
ctx.fillStyle = '#222222';
|
||||
ctx.beginPath();
|
||||
ctx.rect(
|
||||
tX,
|
||||
tY + 3 - (height / 2) - 10,
|
||||
width + 36 + 10,
|
||||
height + 20,
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = 'white';
|
||||
lines.map((line, i) => {
|
||||
ctx.fillText(
|
||||
line,
|
||||
tX + 36,
|
||||
tY + (16 * i) + 16 - (height / 2)
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const composeStickers = ({ stickers, ctx }) => {
|
||||
if (!stickers || stickers.length < 0) return;
|
||||
|
||||
stickers.map(({ x, y, angle, text }) => {
|
||||
composeStickerArrow(ctx, x, y, angle);
|
||||
composeStickerText(ctx, x, y, angle, text);
|
||||
});
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
export const downloadCanvas = (canvas, title) => canvas.toBlob(blob => saveAs(blob, title));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue