kopia lustrzana https://github.com/FacilMap/facilmap
First basic implementation of search in map (not completely tested) (#18)
rodzic
39364e839a
commit
f61080c92c
|
@ -327,6 +327,16 @@ Search for places.
|
|||
* _returns_ (Promise<string|Array<[searchResult](#searchresult)>>): If `data.query` is a URL to a GPX/KML/OSM/GeoJSON
|
||||
file, that file as a string, otherwise an array of search results.
|
||||
|
||||
### `findOnMap(data)`
|
||||
|
||||
Search for markers and lines inside the map.
|
||||
|
||||
* `data` (object): An object with the following properties:
|
||||
* `query` (string): The query string
|
||||
* _returns_ (Promise<Array<[Marker](#marker-1)|[Line](#line-1)>>) An array of (stripped down) marker and line objects.
|
||||
The objects only contain the `id`, `name`, `typeId`, ``lat`/`lon` (for markers), `left`/`top`/`right`/`bottom` (for
|
||||
lines) properties, plus an additional `kind` property that is either `"marker"` or `"line"`.
|
||||
|
||||
### `getRoute(data)`
|
||||
|
||||
Calculate a route between two or more points.
|
||||
|
@ -409,7 +419,7 @@ that line already has the right style.
|
|||
|
||||
Create a line.
|
||||
|
||||
* `data` ([line](#line)): The data of the line to create. An `id` will be assigned by the server
|
||||
* `data` ([line](#line-1)): The data of the line to create. An `id` will be assigned by the server
|
||||
* _returns_ (Promise<[line](#line-1)>): The line as it is on the server, with an `id` assigned and possibly its
|
||||
styles modified by the settings of its type.
|
||||
|
||||
|
@ -504,7 +514,7 @@ A bounding box that describes which part of the map the user is currently viewin
|
|||
|
||||
* `id` (number): The ID of this marker
|
||||
* `lat` (number, min: -90, max: 90): The latitude of this marker
|
||||
* `lon` (number, min: -90, max: 90): The longitude of this marker
|
||||
* `lon` (number, min: -180, max: 180): The longitude of this marker
|
||||
* `name` (string): The name of this marker
|
||||
* `colour` (string): The colour of this marker as a 6-digit hex value, for example `ff0000`
|
||||
* `size` (number, min: 15): The height of the marker in pixels
|
||||
|
@ -537,6 +547,7 @@ separately through `linePoints` events.
|
|||
* `distance` (number): The distance of the line in kilometers (set by the server)
|
||||
* `ascent`, `descent` (number): The total ascent/descent of the line in metres (set by the server)
|
||||
* `time` (number): The time it takes to travel the route in seconds (only if routing mode is `car`, `bicycle` or `pedestrian`) (set by the server)
|
||||
* `left`, `top`, `right`, `bottom` (number): The bounding box of the line (set by the server)
|
||||
* `typeId` (number): The ID of the type of this line
|
||||
* `data` (`{"key", "value"}`): The filled out form fields of the line
|
||||
* `trackPoints`:
|
||||
|
|
|
@ -152,6 +152,10 @@ class Socket {
|
|||
return this._emit("find", data);
|
||||
}
|
||||
|
||||
findOnMap(data) {
|
||||
return this._emit("findOnMap", data);
|
||||
}
|
||||
|
||||
getRoute(data) {
|
||||
return this._emit("getRoute", data);
|
||||
}
|
||||
|
|
|
@ -51,5 +51,6 @@ require("./type")(Database);
|
|||
require("./history")(Database);
|
||||
require("./meta")(Database);
|
||||
require("./route")(Database);
|
||||
require("./search")(Database);
|
||||
|
||||
module.exports = Database;
|
|
@ -42,7 +42,11 @@ module.exports = function(Database) {
|
|||
distance : { type: Sequelize.FLOAT(24, 2).UNSIGNED, allowNull: true },
|
||||
time : { type: Sequelize.INTEGER.UNSIGNED, allowNull: true },
|
||||
ascent : { type: Sequelize.INTEGER.UNSIGNED, allowNull: true },
|
||||
descent : { type: Sequelize.INTEGER.UNSIGNED, allowNull: true }
|
||||
descent : { type: Sequelize.INTEGER.UNSIGNED, allowNull: true },
|
||||
top: this._TYPES.lat,
|
||||
bottom: this._TYPES.lat,
|
||||
left: this._TYPES.lon,
|
||||
right: this._TYPES.lon
|
||||
});
|
||||
|
||||
this._conn.define("LinePoint", {
|
||||
|
@ -278,14 +282,16 @@ module.exports = function(Database) {
|
|||
});
|
||||
},
|
||||
|
||||
_calculateRouting(line, trackPointsFromRoute) {
|
||||
async _calculateRouting(line, trackPointsFromRoute) {
|
||||
let trackPoints;
|
||||
|
||||
if(trackPointsFromRoute) {
|
||||
line.distance = trackPointsFromRoute.distance;
|
||||
line.time = trackPointsFromRoute.time;
|
||||
line.ascent = trackPointsFromRoute.ascent;
|
||||
line.descent = trackPointsFromRoute.descent;
|
||||
|
||||
return Promise.resolve(trackPointsFromRoute.trackPoints);
|
||||
trackPoints = trackPointsFromRoute.trackPoints;
|
||||
} else if(line.mode == "track" && line.trackPoints && line.trackPoints.length >= 2) {
|
||||
line.distance = utils.calculateDistance(line.trackPoints);
|
||||
line.time = null;
|
||||
|
@ -295,27 +301,30 @@ module.exports = function(Database) {
|
|||
for(var i=0; i<line.trackPoints.length; i++)
|
||||
line.trackPoints[i].idx = i;
|
||||
|
||||
return Promise.resolve(line.trackPoints);
|
||||
trackPoints = line.trackPoints;
|
||||
} else if(line.routePoints && line.routePoints.length >= 2 && line.mode && line.mode != "track") {
|
||||
return routing.calculateRouting(line.routePoints, line.mode).then((routeData) => {
|
||||
line.distance = routeData.distance;
|
||||
line.time = routeData.time;
|
||||
line.ascent = routeData.ascent;
|
||||
line.descent = routeData.descent;
|
||||
for(var i=0; i<routeData.trackPoints.length; i++)
|
||||
routeData.trackPoints[i].idx = i;
|
||||
return routeData.trackPoints;
|
||||
});
|
||||
let routeData = await routing.calculateRouting(line.routePoints, line.mode);
|
||||
line.distance = routeData.distance;
|
||||
line.time = routeData.time;
|
||||
line.ascent = routeData.ascent;
|
||||
line.descent = routeData.descent;
|
||||
for(var i=0; i<routeData.trackPoints.length; i++)
|
||||
routeData.trackPoints[i].idx = i;
|
||||
|
||||
trackPoints = routeData.trackPoints;
|
||||
} else {
|
||||
line.distance = utils.calculateDistance(line.routePoints);
|
||||
line.time = null;
|
||||
|
||||
var trackPoints = [ ];
|
||||
trackPoints = [ ];
|
||||
for(var i=0; i<line.routePoints.length; i++) {
|
||||
trackPoints.push(utils.extend({ }, line.routePoints[i], { zoom: 1, idx: i }));
|
||||
}
|
||||
return Promise.resolve(trackPoints);
|
||||
}
|
||||
|
||||
Object.assign(line, utils.calculateBbox(trackPoints));
|
||||
|
||||
return line;
|
||||
}
|
||||
});
|
||||
};
|
|
@ -213,7 +213,29 @@ module.exports = function(Database) {
|
|||
});
|
||||
|
||||
|
||||
return Promise.all([ renameColMigrations, changeColMigrations, addColMigrations, dropdownKeyMigration, elevationMigration, legendMigration ]);
|
||||
// Calculate bounding box for lines
|
||||
let bboxMigration = addColMigrations.then(async () => {
|
||||
if(await this.getMeta("hasBboxes"))
|
||||
return;
|
||||
|
||||
let LinePoint = this._conn.model("LinePoint");
|
||||
|
||||
for(let line of await this._conn.model("Line").findAll()) {
|
||||
let bbox = await Promise.props({
|
||||
top: LinePoint.min("lat", { where: { lineId: line.id } }),
|
||||
bottom: LinePoint.max("lat", { where: { lineId: line.id } }),
|
||||
left: LinePoint.min("lon", { where: { lineId: line.id } }),
|
||||
right: LinePoint.min("lon", { where: { lineId: line.id } })
|
||||
});
|
||||
|
||||
await this._updatePadObject("Line", line.padId, line.id, bbox, true);
|
||||
}
|
||||
|
||||
await this.setMeta("hasBboxes", true);
|
||||
});
|
||||
|
||||
|
||||
return Promise.all([ renameColMigrations, changeColMigrations, addColMigrations, dropdownKeyMigration, elevationMigration, legendMigration, bboxMigration ]);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
const Promise = require("bluebird");
|
||||
const Sequelize = require("sequelize");
|
||||
const similarity = require("string-similarity");
|
||||
|
||||
const utils = require("../utils");
|
||||
|
||||
const Op = Sequelize.Op;
|
||||
|
||||
module.exports = (Database) => {
|
||||
Object.assign(Database.prototype, {
|
||||
|
||||
async search(padId, searchText) {
|
||||
let objects = [].concat(...(await Promise.all([ "Marker", "Line" ].map(async (kind) => {
|
||||
let objs = await this._conn.model(kind).findAll({
|
||||
where: Sequelize.and(
|
||||
{ padId },
|
||||
Sequelize.where(Sequelize.fn("lower", Sequelize.col(`${kind}.name`)), {[Op.like]: `%${searchText.toLowerCase()}%`})
|
||||
),
|
||||
attributes: [ "name", "typeId" ].concat(kind == "Marker" ? [ "lat", "lon" ] : [ "top", "left", "bottom", "right" ])
|
||||
});
|
||||
|
||||
return objs.map((obj) => (Object.assign(JSON.parse(JSON.stringify(obj)), {
|
||||
kind: kind.toLowerCase(),
|
||||
similarity: similarity.compareTwoStrings(searchText, obj.name)
|
||||
})));
|
||||
}))));
|
||||
|
||||
objects.sort((a, b) => (b.similarity - a.similarity));
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
});
|
||||
};
|
|
@ -44,6 +44,7 @@
|
|||
"sequelize": "^4.32.2",
|
||||
"socket.io": "^2.0.4",
|
||||
"stream-combiner": "^0.2.2",
|
||||
"string-similarity": "^1.2.0",
|
||||
"underscore": "^1.8.3",
|
||||
"unzipper": "^0.8.11"
|
||||
},
|
||||
|
|
|
@ -503,6 +503,16 @@ utils.extend(SocketConnection.prototype, {
|
|||
});
|
||||
},
|
||||
|
||||
async findOnMap(data) {
|
||||
if(!utils.stripObject(data, { query: "string" }))
|
||||
throw new Error("Invalid parameters.");
|
||||
|
||||
if(!this.padId)
|
||||
throw new Error("No collaborative map opened.");
|
||||
|
||||
return this.database.search(this.padId, data.query);
|
||||
},
|
||||
|
||||
getRoute: function(data) {
|
||||
return Promise.resolve().then(() => {
|
||||
if(!utils.stripObject(data, { destinations: [ { lat: "number", lon: "number" } ], mode: "string" }))
|
||||
|
|
|
@ -361,6 +361,23 @@ function interceptWriteStream(writeStream) {
|
|||
});
|
||||
}
|
||||
|
||||
function calculateBbox(trackPoints) {
|
||||
let bbox = { top: null, left: null, right: null, bottom: null };
|
||||
|
||||
for(let trackPoint of trackPoints) {
|
||||
if(bbox.top == null || trackPoint.lat > bbox.top)
|
||||
bbox.top = trackPoint.lat;
|
||||
if(bbox.bottom == null || trackPoint.lat < bbox.bottom)
|
||||
bbox.bottom = trackPoint.lat;
|
||||
if(bbox.left == null || trackPoint.lon < bbox.left)
|
||||
bbox.left = trackPoint.lon;
|
||||
if(bbox.right == null || trackPoints.lon > bbox.right)
|
||||
bbox.right = trackPoint.lon;
|
||||
}
|
||||
|
||||
return bbox;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isInBbox : isInBbox,
|
||||
filterStreamPromise : filterStreamPromise,
|
||||
|
@ -376,5 +393,6 @@ module.exports = {
|
|||
streamToArrayPromise: streamToArrayPromise,
|
||||
promiseAuto: promiseAuto,
|
||||
modifyFunction: modifyFunction,
|
||||
interceptWriteStream: interceptWriteStream
|
||||
interceptWriteStream: interceptWriteStream,
|
||||
calculateBbox
|
||||
};
|
|
@ -3228,6 +3228,12 @@ stream-http@^2.7.2:
|
|||
to-arraybuffer "^1.0.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
string-similarity@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-1.2.0.tgz#d75153cb383846318b7a39a8d9292bb4db4e9c30"
|
||||
dependencies:
|
||||
lodash "^4.13.1"
|
||||
|
||||
string-width@^1.0.1, string-width@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
|
|
Ładowanie…
Reference in New Issue