diff --git a/backend/config/db.js b/backend/config/db.js index c87db48..ee1b5f0 100644 --- a/backend/config/db.js +++ b/backend/config/db.js @@ -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}`); diff --git a/backend/models/Route.js b/backend/models/Route.js index 318b8f1..51426b7 100644 --- a/backend/models/Route.js +++ b/backend/models/Route.js @@ -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 }, diff --git a/backend/routes/auth/check.js b/backend/routes/auth/check.js index 39ca59e..4053922 100644 --- a/backend/routes/auth/check.js +++ b/backend/routes/auth/check.js @@ -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(); diff --git a/backend/utils/parse.js b/backend/utils/parse.js index b7df49d..32e884b 100644 --- a/backend/utils/parse.js +++ b/backend/utils/parse.js @@ -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 diff --git a/src/components/maps/RouteRow.jsx b/src/components/maps/RouteRow.jsx index 245bdcd..3c4c988 100644 --- a/src/components/maps/RouteRow.jsx +++ b/src/components/maps/RouteRow.jsx @@ -30,7 +30,7 @@ export const RouteRow = ({
- {(distance && `${distance} km`) || 'N/A'} + {(distance && `${distance} km`) || '0 km'}
diff --git a/src/modules/Editor.js b/src/modules/Editor.js index 498dabe..41a22e3 100644 --- a/src/modules/Editor.js +++ b/src/modules/Editor.js @@ -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; diff --git a/src/modules/Sticker.js b/src/modules/Sticker.js index 5cf1099..3f49231 100644 --- a/src/modules/Sticker.js +++ b/src/modules/Sticker.js @@ -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} > - {this.generateStickerSVG(sticker)} + {this.generateStickerSVG(set, sticker)}
( -
{ + return ( +
- ); + /> + ); + }; dumpData = () => ({ angle: this.angle, latlng: { ...this.marker.getLatLng() }, sticker: this.sticker, + set: this.set, text: this.text, }); diff --git a/src/modules/Stickers.js b/src/modules/Stickers.js index f464ee3..aa94c64 100644 --- a/src/modules/Stickers.js +++ b/src/modules/Stickers.js @@ -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, }); diff --git a/src/redux/user/sagas.js b/src/redux/user/sagas.js index bf5b90f..87f75f6 100644 --- a/src/redux/user/sagas.js +++ b/src/redux/user/sagas.js @@ -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'); } diff --git a/src/styles/stickers.less b/src/styles/stickers.less index f298944..6badde5 100644 --- a/src/styles/stickers.less +++ b/src/styles/stickers.less @@ -162,7 +162,7 @@ .sticker-desc { min-width: 60px; - + z-index: -1; height: auto; background: #222222; position: absolute; diff --git a/src/utils/renderer.js b/src/utils/renderer.js index a726e70..a9ab3d7 100644 --- a/src/utils/renderer.js +++ b/src/utils/renderer.js @@ -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));