let ol = require('openlayers');
let Location = require('./../types/location');
/**
* Класс RoutingInteraction предназначен для реализации взаимодействия пользователя и карты, при построении маршрутов
*/
class RoutingInteraction {
constructor(params) {
this.map = params.map;
this.events = {};
}
setMap(map) {
this.map = map;
}
addLocation(location) {
let self = this;
let feature = new ol.Feature({
id: location.id,
title: location.title,
address: location.address,
geometry: new ol.geom.Point(location.coordinate)
});
let source = self.getSource();
source.addFeature(feature);
source.on("addfeature", () => {
let coordinates = self.getCoordinates();
let features = self.getSource().getFeatures();
let locations = self.featuresToLocations(features);
self.emit("route-location-map-added", {
status: true,
coordinates: coordinates,
locations: locations
});
})
}
removeLocation(index) {
let self = this;
let features = self.getSource().getFeatures();
let feature = features[index];
this.getSource().removeFeature(feature);
this.getSource().on("removefeature", function () {
let coordinates = self.getCoordinates();
let features = self.getSource().getFeatures();
let locations = self.featuresToLocations(features);
self.emit("route-locations-changed", {
status: true,
coordinates: coordinates,
locations: locations
});
});
}
isValid() {
let flag = this.map === undefined ? false : true;
return flag;
}
getSource() {
return this.stopsLayer.getSource();
}
getMap() {
return this.map.map;
}
initInteractions() {
let self = this;
let {stopsSource, map} = this.initLayers();
self.modify = new ol.interaction.Modify({source: stopsSource});
map.addInteraction(self.modify);
self.draw = new ol.interaction.Draw({
source: stopsSource,
type: "Point"
});
map.addInteraction(self.draw);
self.snap = new ol.interaction.Snap({source: stopsSource});
map.addInteraction(self.snap);
self.draw.on("drawend", async function (evt) {
let features = self.getSource().getFeatures();
features.push(evt.feature);
let coordinates = features.map((item) => {
return ol.proj.toLonLat(item.getGeometry().getCoordinates());
});
let locations = self.featuresToLocations(features);
/**
* Событие возникает при добавлнии нового маршрутного пункта пользователем с карты
* @event RoutingInteraction#route-location-user-added
*/
self.emit("route-location-map-added", {
status: true,
coordinates: coordinates,
locations: locations
});
});
self.modify.on("modifyend", async function () {
let coordinates = self.getCoordinates();
let locations = self.featuresToLocations(self.getSource().getFeatures());
/**
* Событие возникает при изменении местоположения маршрутного пункта пользователем с карты
* @event RoutingInteraction#route-locations-changed
*/
self.emit("route-locations-changed", {
status: true,
coordinates: coordinates,
locations: locations
});
});
}
initLayers() {
let self = this;
let stopsSource = new ol.source.Vector();
let routeSource = new ol.source.Vector();
let alternativeRouteSource = new ol.source.Vector();
self.stopsLayer = new ol.layer.Vector({
source: stopsSource,
style: new ol.style.Style({
fill: new ol.style.Fill({
color: '#27dd38'
}),
stroke: new ol.style.Stroke({
color: 'rgba(100,100,255, 0.7)',
width: 10
}),
image: new ol.style.Circle({
radius: 8,
fill: new ol.style.Fill({
color: '#ffffff'
}),
stroke: new ol.style.Stroke({
color: "#ff1ee9",
width: 3
})
})
})
});
self.routeLayer = new ol.layer.Vector({
source: routeSource,
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(100,100,255, 0.7)',
width: 10
}),
image: new ol.style.Circle({
radius: 8,
fill: new ol.style.Fill({
color: '#ffffff'
}),
stroke: new ol.style.Stroke({
color: "#ff1ee9",
width: 3
})
})
})
});
self.alternativeRouteLayer = new ol.layer.Vector({
source: alternativeRouteSource,
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(255,0,200, 0.7)',
width: 8
}),
image: new ol.style.Circle({
radius: 8,
fill: new ol.style.Fill({
color: '#ffffff'
}),
stroke: new ol.style.Stroke({
color: "#ff1ee9",
width: 3
})
})
})
});
let map = self.getMap();
map.addLayer(self.routeLayer);
map.addLayer(self.alternativeRouteLayer);
map.addLayer(self.stopsLayer);
return {stopsSource, map};
}
/**
* Метод, перерисовывющий маршрут на карте
*/
drawRoute(data) {
let self = this;
let routeFeature;
let alternativeRouteFeatures;
let layer = self.routeLayer;
let alternativeLayer = self.alternativeRouteLayer;
if (data === false || data.status === false) return data;
self.clearRoute();
let routeGeometry = this.getRouteGeometry(data);
if (routeGeometry) {
routeFeature = new ol.Feature({
geometry: routeGeometry
});
layer.getSource().addFeature(routeFeature);
}
let alternativeGeometries = this.getAlternativeRouteGeometry(data);
if (alternativeGeometries) {
alternativeRouteFeatures = alternativeGeometries.map((item) => {
return new ol.Feature({geometry: item});
});
alternativeLayer.getSource().addFeatures(alternativeRouteFeatures);
}
/**
* Событие возникает перерисовке маршрута на карте
* @event RoutingInteraction#route-drawend
*/
self.emit("route-drawend", {
status: true,
feature: routeFeature
});
}
getRouteGeometry(data) {
try {
let coordinates = data.result.route.geometry.map((item) => {
let coordinate = ol.proj.transform([item[1], item[0]], 'EPSG:4326', 'EPSG:3857');
return coordinate;
});
let geometry = new ol.geom.LineString(coordinates);
return geometry;
}
catch (e) {
}
return undefined;
}
getAlternativeRouteGeometry(data) {
let result = [];
try {
for (let i = 0; i < data.result.alternative.geometry.length; i++) {
let geom = data.result.alternative.geometry[i];
let coordinates = geom.map((item) => {
let coordinate = ol.proj.transform([item[1], item[0]], 'EPSG:4326', 'EPSG:3857');
return coordinate;
});
let geometry = new ol.geom.LineString(coordinates);
result.push(geometry);
}
}
catch (e) {
}
return result;
}
/**
* Метод, приводящий к очистке путевых точек
*/
clearLocations() {
let self = this;
self.locations = [];
self.stopsLayer.getSource().clear();
/**
* Событие, возникающее при очистке маршрутных точек
* @event RoutingInteraction#route-clear-locations
*/
self.emit("route-clear-locations", {
locations: []
});
}
/**
* Метод очищает все построенные линии маршрутов, но не очищает маршрутные точки.
*/
clearRoute() {
let self = this;
let source = self.routeLayer.getSource();
source.clear();
source = self.alternativeRouteLayer.getSource();
source.clear();
/**
* Событие, возникающее при очистке маршрута
* @event RoutingInteraction#route-cleared
*/
self.emit("route-cleared", {
route: undefined
})
}
getCoordinates() {
let locations = this.getSource().getFeatures();
let coordinates = locations.map((item) => {
return ol.proj.toLonLat(item.getGeometry().getCoordinates());
});
return coordinates;
}
featuresToLocations(data) {
let locations = data.map((item) => {
let location = new Location({
id: item.get("id"),
title: item.get("title"),
address: item.get("address"),
coordinates: item.getGeometry().getCoordinates(),
});
return location;
});
return locations;
}
start() {
this.initInteractions();
}
stop() {
let self = this;
let map = self.map.map;
map.removeInteraction(self.draw);
map.removeInteraction(self.modify);
map.removeInteraction(self.snap);
map.removeLayer(self.stopsLayer);
map.removeLayer(self.routeLayer);
map.removeLayer(self.alternativeRouteLayer);
}
/**
* Подписка на события
* @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];
console.log(eventName, context);
if (listener && typeof listener === "function") {
listener(context);
}
}
}
module.exports = RoutingInteraction;