RoutesMaker/Public/ecma/Drivers/LeafLetOSMDriver.ecma.js

240 lines
7.2 KiB
JavaScript

"use strict";
import {MapDriverInterface} from "../Interfaces/MapDriverInterface.ecma.js";
import {EventModel} from "../Models/EventModel.ecma.js";
import {Utils} from "../Utils/Utils.ecma.js";
/**
* @typedef {import("../Application/RoutesMaker.ecma.js").RoutesMaker} RoutesMaker
* @typedef {import("../Models/DotModel.ecma.js").DotModel} DotModel
*/
/**
* @class
* @constructor
* @param {!RoutesMaker} routes_maker
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access public
* @static
*/
export const LeafLetOSMDriver = (function(){
/**
* @constructs LeafLetOSMDriver
* @param {!RoutesMaker} routes_maker
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {void}
* @access public
* @static
*/
const LeafLetOSMDriver = function(routes_maker, inputs = null){
/** @type {LeafLetOSMDriver} */
const self = this;
/** @type {L.Map} */
this.map = null;
/** @type {HTMLElement} */
this.box = null;
/** @type {EventModel} */
this.on_click = new EventModel();
/**
* @returns {void}
* @access private
*/
const constructor = () => {
MapDriverInterface.check(self);
};
/**
* @param {!HTMLElement} box
* @returns {void}
* @access public
*/
this.build = box => {
/** @type {string} */
let id;
if(box.hasAttribute("id"))
id = box.getAttribute("id");
else
box.setAttribute("id", id = routes_maker.random_keys.get());
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom : 19,
attribution : '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(self.map = L.map(id).setView(routes_maker.get_user_coordenates(), 13));
routes_maker.base.on_change.add(_ => {
self.map.invalidateSize(true);
});
self.map.on("click", event => {
self.on_click.execute(event.latlng.lng, event.latlng.lat);
});
};
const set_value = (object, dom, name, value) => {
object[dom] && object[dom].setAttribute(name, value);
};
const update_object_attributes = (item, object) => {
for(const key in item.attributes){
/** @type {string} */
const name = "data-" + Utils.to_kebab(key);
["_path", "_icon", "_shadow"].forEach(dom => {
set_value(object, dom, name, item.attributes[key]);
});
};
}
const set_attributes = (item, object) => {
object.on("add", () => {
update_object_attributes(item, object);
});
update_object_attributes(item, object);
};
this.update_attributes = item => {
["marker", "line"].forEach(key => {
item[key] && update_object_attributes(item, item[key]);
});
};
/**
* @param {!DotModel} dot
* @returns {void}
* @access public
*/
this.add_dot = (dot, attributes = {}) => {
/** @type {[number, number]} */
const point = dot.get_point();
(dot.marker = L.marker(point, {draggable : true})).addTo(self.map);
self.redraw_dot_lines(dot);
dot.marker.on("click", event => {
dot.on_click.execute();
});
dot.marker.on("dragend", event => {
/** @type {L.LatLng} */
const coordenates = event.target.getLatLng();
dot.on_drop.execute(coordenates.lng, coordenates.lat);
});
set_attributes(dot, dot.marker);
};
/**
* @param {!DotModel} dot
* @returns {void}
* @access public
*/
this.remove_dot_line = dot => {
if(dot.line){
self.map.removeLayer(dot.line);
dot.line = null;
};
};
/**
* @param {!DotModel} dot
* @returns {void}
* @access public
*/
this.remove_dot_lines = dot => {
dot.i && self.remove_dot_line(dot);
dot.i + 1 < dot.route.dots.length && self.remove_dot_line(dot.route.dots[dot.i + 1]);
};
/**
* @param {!DotModel} dot
* @returns {void}
* @access public
*/
this.redraw_dot_lines = dot => {
/** @type {[number, number]} */
const point = dot.get_point(),
/** @type {DotModel|null} */
previous = dot.i ? dot.route.dots[dot.i - 1] : null,
/** @type {DotModel|null} */
next = dot.i + 1 < dot.route.dots.length ? dot.route.dots[dot.i + 1] : null;
self.remove_dot_lines(dot);
if(previous){
(dot.line = L.polyline([previous.get_point(), point])).addTo(self.map);
set_attributes(dot, dot.line);
};
if(next){
(next.line = L.polyline([point, next.get_point()])).addTo(self.map);
set_attributes(dot, next.line);
};
};
/**
* @param {!DotModel} dot
* @returns {void}
* @access public
*/
this.remove_dot = dot => {
self.remove_dot_lines(dot);
self.map.removeLayer(dot.marker);
};
this.create_overlay = overlay => {
const item = document.createElementNS("http://www.w3.org/2000/svg", "svg");
item.innerHTML = overlay.data.replace(/<\/?svg([^>]*)>/gi, (_, data) => {
data.matchAll(/ ([^= ]+)="([^"]*)"/g).forEach(([_, key, value]) => {
item.setAttribute(key, value);
});
return "";
}).replace(/(<([^ >]+) [^\/>]+) \/>/g, "$1></$2>");
(overlay.item = L.svgOverlay(item, L.latLngBounds(overlay.position.get_point(), overlay.size.get_point()))).addTo(self.map);
(overlay.from = L.marker(overlay.position.get_point(), {draggable : true})).addTo(self.map);
(overlay.to = L.marker(overlay.size.get_point(), {draggable : true})).addTo(self.map);
overlay.from.on("dragend", event => {
/** @type {L.LatLng} */
const coordenates = event.target.getLatLng();
overlay.on_change_position.execute(coordenates.lng, coordenates.lat);
});
overlay.to.on("dragend", event => {
/** @type {L.LatLng} */
const coordenates = event.target.getLatLng();
overlay.on_change_size.execute(coordenates.lng, coordenates.lat);
});
};
this.update_overalay = overlay => {
overlay.item.setBounds(L.latLngBounds(overlay.position.get_point(), overlay.size.get_point()));
};
constructor();
};
return LeafLetOSMDriver;
})();