let axios = require('axios');
let RoutingResult = require('./types/directionResult');
let RoutingInteraction = require('./interactors/commonInteraction');
/**
* Класс Routing предназначер для вычисления маршрутов
*/
class Routing {
/**
* @param params {object} - опции создания экземпляра класса
* @param params.locations {array} - стартовый массив путевых точек, по умолчанию пустой массив
*/
constructor(params) {
this.params = params;
this.store = {};
this.locations = [];
this.events = {};
this.started = false;
this.interaction = params.interaction || new RoutingInteraction(params);
this.initEvents();
}
/**
* Запуск работы модуля маршрутизации
*/
start() {
let self = this;
if (self.started) return self.started;
self.started = true;
let locations = self.locations;
if (self.interaction) self.interaction.start({locations: locations});
/**
* Cобытие, возникающее при старте (инициализации) модуля роутинга
* @event Routing#routing-started
* @return {object}
*/
self.emit("routing-started", {
status: true
});
}
/**
* Остановка работы модуля
*/
stop() {
let self = this;
if (self.started === false) return;
self.started = false;
self.interaction.stop();
/**
* @event Routing#routing-stopped - Событие, возникающее при остановке действий с роутингом
*/
self.emit("routing-stopped", {
status: true
})
}
/**
* Метод, вычисляющий маршрут
* @param params {object} - опции поиска
* @param params.locations {array} - массив путевых точек
* @return {Promise.<*>}
*/
async calc(params) {
let self = this;
if (params.coordinates.length < 2) {
/**
* @event Routing#route-locations-not-enough
* Возникает в случае, если параметров для расчета маршрута недостаточно (0 или 1 точка)
*/
self.emit("route-locations-not-enough", {
locationsCount: params.coordinates.length,
route: undefined,
status: false
});
return {
route: undefined,
locationsCount: params.coordinates.length,
status: false
};
}
let locations = params.coordinates.map((item) => {
return "loc=" + item[1] + "," + item[0];
}).join("&");
const zParam = "z=50";
const outParam = "output=json";
const instructionsParam = "instructions=true";
const compressionParam = "compression=false";
let query = [zParam, outParam, instructionsParam, compressionParam, locations].join("&");
const requestUrl = self.params.url + "/viaroute?" + query;
let action = (await axios(requestUrl)).data;
self.store.route = new RoutingResult(action);
/**
* Событие возникает перерасчете маршрута
* @event Routing#route-calculated
*/
self.emit("route-calculated", {
route: self.store.route,
status: true
});
return self.store.route;
}
/**
* Возврашает текущий набор маршуртных точек
* @return {Array|*}
*/
getLocations() {
return this.locations;
}
/**
* Добавляет маршуртную точку
* @param {RoutingLocation} data
*/
addLocation(data) {
let location = data;
this.locations.push(location);
/**
* @event Routing#route-location-api-added
* Возникает при программном добавлении маршрутной точки
*/
this.emit("route-location-api-added", {
location: location
});
if (this.interaction) this.interaction.addLocation(location);
}
/**
* Удаляет маршрутную точку по ее индексу
* @param index
*/
removeLocation(index) {
this.locations = this.locations.filter((item, idx) => {
if (index === idx) return false;
return true;
});
/**
* @event Routing#route-location-api-added
* Возникает при программном удалении маршрутной точки
*/
this.emit("route-location-api-removed", {
locationId: index
});
if (this.interaction) this.interaction.removeLocation(index);
if (this.locations.length < 2) this.interaction.clearRoute();
}
updateLocations(locations) {
this.locations = locations;
}
clear() {
this.clearRoute();
this.clearLocations();
}
clearRoute() {
if (this.interaction) this.interaction.clearRoute();
}
clearLocations() {
if (this.interaction) this.interaction.clearLocations();
}
/**
* @param params {object}
* @param params.map {Map} - ссылка на экземпляр карты
*/
setOptions(params) {
if (params.map && this.interaction !== undefined) this.interaction.setMap(params.map);
}
initEvents() {
let self = this;
self.events = {};
if (self.interaction) {
self.interaction.on("route-location-map-added", async function (data) {
let route = await self.calc({coordinates: data.coordinates});
self.updateLocations(data.locations);
if (self.interaction.isValid()) self.interaction.drawRoute(route);
});
self.interaction.on("route-locations-changed", async function (data) {
let route = await self.calc({coordinates: data.coordinates});
self.updateLocations(data.locations);
if (self.interaction.isValid()) self.interaction.drawRoute(route);
});
}
}
/**
* Подписка на события
* @param eventName - имя события
* @param listener - callback
*/
on(eventName, listener) {
let self = this;
let eventStore = self.events;
eventStore[eventName] = listener;
}
/**
* Выключение подписки на событие
* @param eventName - имя события
*/
off(eventName) {
let self = this;
let eventStore = self.events;
if (eventStore[eventName]) delete eventStore[eventName];
}
/**
* Инициация события с контекстом
* @param eventName - имя события
* @param context - контекст события
*/
emit(eventName, context) {
let self = this;
let eventStore = self.events;
let listener = eventStore[eventName];
if (listener && typeof listener === "function") {
listener(context);
}
}
}
module.exports = Routing;