diff --git a/Public/ecma/Application/RoutesMaker.ecma.js b/Public/ecma/Application/RoutesMaker.ecma.js index 680f108..8120295 100644 --- a/Public/ecma/Application/RoutesMaker.ecma.js +++ b/Public/ecma/Application/RoutesMaker.ecma.js @@ -7,6 +7,7 @@ import {MenuView} from "../Views/MenuView.ecma.js"; import {MapView} from "../Views/MapView.ecma.js"; import {RoutesManager} from "../Managers/RoutesManager.ecma.js"; import {RandomKeysManager} from "../Managers/RandomKeysManager.ecma.js"; +import {LayersManager} from "../Managers/LayersManager.ecma.js"; /** * @callback routes_maker_ready_callback @@ -42,9 +43,6 @@ export const RoutesMaker = (function(){ /** @type {number} */ longitude = 0; - /** @type {HTMLElement|null} */ - this.item_self = null; - /** @type {EventModel} */ this.on_ready = new EventModel(); @@ -58,6 +56,8 @@ export const RoutesMaker = (function(){ this.random_keys = new RandomKeysManager(); /** @type {RoutesManager} */ this.routes = new RoutesManager(self); + /** @type {LayersManager} */ + this.layers = new LayersManager(self); const constructor = () => { self.on_ready.add(callback); @@ -96,6 +96,19 @@ export const RoutesMaker = (function(){ */ this.get_user_coordenates = () => [latitude, longitude]; + this.alert = (text, callback) => { + alert(text); + Utils.execute(callback); + }; + + this.confirm = (text, ok_callback, wrong_callback) => { + Utils.execute(confirm(text) ? ok_callback : wrong_callback); + }; + + this.input_text = (text, callback) => { + Utils.execute(callback, prompt(text)); + }; + constructor(); }; diff --git a/Public/ecma/Drivers/LeafLetOSMDriver.ecma.js b/Public/ecma/Drivers/LeafLetOSMDriver.ecma.js index 05a1870..ef47122 100644 --- a/Public/ecma/Drivers/LeafLetOSMDriver.ecma.js +++ b/Public/ecma/Drivers/LeafLetOSMDriver.ecma.js @@ -2,6 +2,7 @@ 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 @@ -76,12 +77,42 @@ export const LeafLetOSMDriver = (function(){ }; + 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 => { + this.add_dot = (dot, attributes = {}) => { /** @type {[number, number]} */ const point = dot.get_point(); @@ -100,6 +131,7 @@ export const LeafLetOSMDriver = (function(){ dot.on_drop.execute(coordenates.lng, coordenates.lat); }); + set_attributes(dot, dot.marker); }; @@ -140,8 +172,14 @@ export const LeafLetOSMDriver = (function(){ next = dot.i + 1 < dot.route.dots.length ? dot.route.dots[dot.i + 1] : null; self.remove_dot_lines(dot); - previous && (dot.line = L.polyline([previous.get_point(), point])).addTo(self.map); - next && (next.line = L.polyline([point, next.get_point()])).addTo(self.map); + 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); + }; }; @@ -155,6 +193,45 @@ export const LeafLetOSMDriver = (function(){ 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>"); + + (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(); }; diff --git a/Public/ecma/Managers/LayersManager.ecma.js b/Public/ecma/Managers/LayersManager.ecma.js new file mode 100644 index 0000000..107957a --- /dev/null +++ b/Public/ecma/Managers/LayersManager.ecma.js @@ -0,0 +1,58 @@ +"use strict"; + +import {LayerModel} from "../Models/LayerModel.ecma.js"; +import {Utils} from "../Utils/Utils.ecma.js"; + +export const LayersManager = (function(){ + + const LayersManager = function(routes_maker){ + + const layers = {}; + + this.get = key => layers[key = Utils.to_key(key)] ? layers[key] : null; + + this.add = (name, data, key = null) => { + + let layer = null; + + (key || (key = Utils.to_key(name))) && + !layers[key] && + (layer = layers[key] = new LayerModel(routes_maker, name, key, data)); + + return layer; + }; + + this.remove = key => { + if(layers[key = Utils.to_key(key)]) + delete layers[key]; + }; + + this.get_data = () => Object.keys(layers).reduce((dictionary, key) => { + + dictionary[key] = [layers[key].name, layers[key].dots.map(dot => [dot.longitude, dot.latitude])]; + + return dictionary; + }, {}); + + this.select = name => { + for(const key in layers){ + + const ok = key == name; + + layers[key].dots.forEach(dot => { + dot.selected(ok); + }); + + }; + }; + + this.visible = (name, ok) => { + layers[name].dots.forEach(dot => { + dot.visible(ok); + }); + }; + + }; + + return LayersManager; +})(); \ No newline at end of file diff --git a/Public/ecma/Managers/RoutesManager.ecma.js b/Public/ecma/Managers/RoutesManager.ecma.js index 8372ae9..a835bfe 100644 --- a/Public/ecma/Managers/RoutesManager.ecma.js +++ b/Public/ecma/Managers/RoutesManager.ecma.js @@ -1,36 +1,109 @@ "use strict"; -import {RouteModel} from "../Models/RouteModel.ecma.js"; +/** + * @typedef {import("../Application/RoutesMaker.ecma.js").RoutesMaker} RoutesMaker + */ +import {RouteModel} from "../Models/RouteModel.ecma.js"; +import {Utils} from "../Utils/Utils.ecma.js"; + +/** + * @class + * @constructor + * @param {!RoutesMaker} routes_maker + * @returns {void} + * @access public + * @static + */ export const RoutesManager = (function(){ + /** + * @constructs RoutesManager + * @param {!RoutesMaker} routes_maker + * @returns {void} + * @access public + * @static + */ const RoutesManager = function(routes_maker){ + /** @type {Object.} */ const routes = {}; - this.get = key => routes[key = RouteModel.to_key(key)] ? routes[key] : null; + /** + * @param {!string} key + * @returns {RouteModel|null} + * @access public + */ + this.get = key => routes[key = Utils.to_key(key)] ? routes[key] : null; + /** + * @param {!string} name + * @param {!string} key + * @returns {RouteModel} + * @access public + */ this.add = (name, key = null) => { + /** @type {RouteModel|null} */ let route = null; - (key || (key = RouteModel.to_key(name))) && + (key || (key = Utils.to_key(name))) && !routes[key] && (route = routes[key] = new RouteModel(routes_maker, name, key)); return route; }; + /** + * @param {!string} key + * @returns {void} + * @access public + */ this.remove = key => { - if(routes[key = RouteModel.to_key(key)]) + if(routes[key = Utils.to_key(key)]) delete routes[key]; }; + /** + * @returns {Object.} + * @access public + */ this.get_data = () => Object.keys(routes).reduce((dictionary, key) => { + dictionary[key] = [routes[key].name, routes[key].dots.map(dot => [dot.longitude, dot.latitude])]; + return dictionary; }, {}); + /** + * @param {!string} name + * @returns {void} + */ + this.select = name => { + for(const key in routes){ + + /** @type {boolean} */ + const ok = key == name; + + routes[key].dots.forEach(dot => { + dot.selected(ok); + }); + + }; + }; + + /** + * @param {!string} name + * @param {!boolean} ok + * @returns {void} + * @access public + */ + this.visible = (name, ok) => { + routes[name].dots.forEach(dot => { + dot.visible(ok); + }); + }; + }; return RoutesManager; diff --git a/Public/ecma/Models/CoordenatesModel.ecma.js b/Public/ecma/Models/CoordenatesModel.ecma.js new file mode 100644 index 0000000..db8f8d2 --- /dev/null +++ b/Public/ecma/Models/CoordenatesModel.ecma.js @@ -0,0 +1,95 @@ +"use strict"; + +/** + * @class + * @constructor + * @param {!number} [longitude = 0] + * @param {!number} [latitude = 0] + * @returns {void} + * @access public + * @static + */ +export const CoordenatesModel = (function(){ + + /** + * @constructs CoordenatesModel + * @param {!number} [longitude = 0] + * @param {!number} [latitude = 0] + * @returns {void} + * @access private + * @static + */ + const CoordenatesModel = function(longitude = 0, latitude = 0){ + + /** @type {CoordenatesModel} */ + const self = this; + + /** @type {number} */ + this.latitude = latitude; + /** @type {number} */ + this.longitude = longitude; + + /** + * @param {...CoordenatesModel} [points] + * @returns {number} + * @access public + */ + this.get_distance_to = (...points) => CoordenatesModel.get_points_distance(self, ...points); + + this.get_point = () => [self.latitude, self.longitude]; + + }; + + /** @type {number} */ + CoordenatesModel.PI_RADIANS = Math.PI / 180; + /** @type {number} */ + CoordenatesModel.POLAR_RADIUS = 6356752; // Polar Earth radius- + /** @type {number} */ + CoordenatesModel.ECUATORIAL_RADIUS = 6378137; // Ecuatorial Earth radius- + + /** + * @param {!CoordenatesModel} from + * @param {!CoordenatesModel} to + * @param {?number} [radius = null] + * @returns {number} + * @access public + * @static + */ + CoordenatesModel.get_distance = (from, to, radius = null) => { + + /** @type {number} */ + const angle = ( + Math.sin((from.latitude - to.latitude) * CoordenatesModel.PI_RADIANS / 2) ** 2 + + Math.cos(from.latitude * CoordenatesModel.PI_RADIANS) * Math.cos(to.latitude * CoordenatesModel.PI_RADIANS) * + Math.sin((from.longitude - to.longitude) * CoordenatesModel.PI_RADIANS / 2) ** 2 + ); + + return (radius || (CoordenatesModel.POLAR_RADIUS + Math.sin( + (Math.abs(from.latitude) + Math.abs(to.latitude)) * .5 + ) * ( + CoordenatesModel.ECUATORIAL_RADIUS - CoordenatesModel.POLAR_RADIUS + ))) * 2 * Math.atan2(angle ** .5, (1 - angle) ** .5); + }; + + /** + * @param {...CoordenatesModel} points + * @returns {number} + * @access public + * @static + */ + CoordenatesModel.get_points_distance = (...points) => { + + /** @type {CoordenatesModel|null} */ + let last = null; + + return points.reduce((distance, coordenates) => { + + last && (distance += CoordenatesModel.get_distance(last, coordenates)); + last = coordenates; + + return distance; + }, 0); + }; + + return CoordenatesModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/DotModel.ecma.js b/Public/ecma/Models/DotModel.ecma.js index 3975dd0..578801e 100644 --- a/Public/ecma/Models/DotModel.ecma.js +++ b/Public/ecma/Models/DotModel.ecma.js @@ -51,6 +51,14 @@ export const DotModel = (function(){ /** @type {number} */ this.distance = 0; + /** @type {object.} */ + this.attributes = { + /** @type {boolean} */ + visible : true, + /** @type {boolean} */ + selected : true + }; + /** @type {EventModel} */ this.on_change = new EventModel(); /** @type {EventModel} */ @@ -74,35 +82,6 @@ export const DotModel = (function(){ self.recalculate_distance(); }); self.recalculate_distance(); - - // self.marker.addTo(map); - // dots.length && (self.line = L.polyline([dots[dots.length - 1].get_dot(), self.get_dot()]).addTo(self.map)); - // self.marker.on("click", event => { - // self.remove(); - // }); - // self.marker.on("dragend", event => { - - // /** @type {L.LatLng} */ - // const coordenates = event.target.getLatLng(); - - // self.longitude = coordenates.lng; - // self.latitude = coordenates.lat; - - // self.remove_lines_linked(); - - // self.i < self.dots.length - 1 && (self.dots[self.i + 1].line = L.polyline([ - // self.dots[self.i + 1].get_dot(), - // self.get_dot() - // ])).addTo(self.map); - // self.i && (self.dots[self.i].line = L.polyline([ - // self.get_dot(), - // self.dots[self.i - 1].get_dot() - // ])).addTo(self.map); - - // self.recalculate_distance(); - - // }); - // self.recalculate_distance(); }; /** @@ -111,32 +90,6 @@ export const DotModel = (function(){ */ this.get_point = () => [self.latitude, self.longitude]; - // /** - // * @returns {void} - // * @access public - // */ - // this.remove_line = () => { - // if(self.line){ - // self.map.removeLayer(self.line); - // self.line = null; - // }; - // }; - - // /** - // * @returns {void} - // * @access public - // */ - // self.remove_lines_linked = () => { - - // /** @type {number} */ - // const l = self.dots.length; - - // [self.i, self.i + 1].forEach(i => { - // i && i < l && self.dots[i].remove_line(); - // }); - - // }; - /** * @returns {void} * @access public @@ -153,19 +106,6 @@ export const DotModel = (function(){ not_unique && route.routes_maker.map.driver.redraw_dot_lines(route.dots[self.i]); not_unique && route.dots[self.i].recalculate_distance(); - // self.remove_lines_linked(); - // self.i && self.i < self.dots.length - 1 && (self.dots[self.i + 1].line = L.polyline([ - // self.dots[self.i + 1].get_dot(), - // self.dots[self.i - 1].get_dot() - // ])).addTo(self.map); - // self.dots.splice(self.i, 1); - // console.log(["A", self.distance]); - // self.dots[self.i + 1].recalculate_distance(); - // console.log(["B", self.distance]); - // self.map.removeLayer(self.marker); - // self.dots.slice(self.i).forEach(dot => { - // dot.i --; - // }); }; /** @@ -199,6 +139,20 @@ export const DotModel = (function(){ }; + const update_attributes = () => { + route.routes_maker.map.driver.update_attributes(self) + }; + + this.selected = ok => { + self.attributes.selected = ok; + update_attributes(); + }; + + this.visible = ok => { + self.attributes.visible = ok; + update_attributes(); + }; + constructor(); }; diff --git a/Public/ecma/Models/LayerItemModel.ecma.js b/Public/ecma/Models/LayerItemModel.ecma.js new file mode 100644 index 0000000..2122e18 --- /dev/null +++ b/Public/ecma/Models/LayerItemModel.ecma.js @@ -0,0 +1,96 @@ +"use strict"; + +/** + * @typedef {import("./LayerModel.ecma.js").LayerModel} LayerModel + */ + +import {MapDriverInterface} from "../Interfaces/MapDriverInterface.ecma.js"; +import {CoordenatesModel} from "./CoordenatesModel.ecma.js"; +import {EventModel} from "./EventModel.ecma.js"; + +/** + * @class + * @constructor + * @param {!LayerModel} layer + * @param {!string} name + * @param {!string} key + * @param {!string} data + * @returns {void} + * @access public + * @static + */ +export const LayerItemModel = (function(){ + + /** + * @constructs LayerItemModel + * @param {!LayerModel} layer + * @param {!string} name + * @param {!string} key + * @param {!string} data + * @returns {void} + * @access private + * @static + */ + const LayerItemModel = function(layer, name, key, data, position, size){ + + /** @type {LayerItemModel} */ + const self = this; + + /** @type {LayerModel} */ + this.layer = layer; + /** @type {string} */ + this.key = key; + /** @type {string} */ + this.name = name; + /** @type {string} */ + this.data = data; + /** @type {MapDriverInterface|null} */ + this.item = null; + /** @type {MapDriverInterface|null} */ + this.from = null; + /** @type {MapDriverInterface|null} */ + this.to = null; + /** @type {CoordenatesModel} */ + this.position = position; + /** @type {CoordenatesModel} */ + this.size = size; + + /** @type {object.} */ + this.attributes = { + /** @type {boolean} */ + visible : true, + /** @type {boolean} */ + selected : true + }; + + /** @type {EventModel} */ + this.on_change_position = new EventModel(); + /** @type {EventModel} */ + this.on_change_size = new EventModel(); + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + self.on_change_position.add((_, longitude, latitude) => { + self.position = new CoordenatesModel(longitude, latitude); + update_form(); + }); + self.on_change_size.add((_, longitude, latitude) => { + self.size = new CoordenatesModel(longitude, latitude); + update_form(); + }); + layer.routes_maker.map.driver.create_overlay(self); + }; + + const update_form = () => { + layer.routes_maker.map.driver.update_overalay(self); + }; + + constructor(); + + }; + + return LayerItemModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/LayerModel.ecma.js b/Public/ecma/Models/LayerModel.ecma.js new file mode 100644 index 0000000..4ead4d2 --- /dev/null +++ b/Public/ecma/Models/LayerModel.ecma.js @@ -0,0 +1,127 @@ +"use strict"; + +/** + * @typedef {import("../Application/RoutesMaker.ecma.js").RoutesMaker} RoutesMaker + */ + +import {LayerItemModel} from "./LayerItemModel.ecma.js"; +import {CoordenatesModel} from "./CoordenatesModel.ecma.js"; +import {Utils} from "../Utils/Utils.ecma.js"; + +/** + * @callback layer_model_add_callback + * @param {!LayerModel} + */ + +/** + * @class + * @constructor + * @param {!RoutesMaker} routes_maker + * @param {!string} name + * @param {!string} key + * @param {?string} [data = null] + * @param {?layer_model_add_callback} [callback = null] + * @returns {void} + * @access public + * @static + */ +export const LayerModel = (function(){ + + /** + * @constructs LayerModel + * @param {!RoutesMaker} routes_maker + * @param {!string} name + * @param {!string} key + * @param {?string} [data = null] + * @param {?layer_model_add_callback} [callback = null] + * @returns {void} + * @access public + * @static + */ + const LayerModel = function(routes_maker, name, key, data = null, callback = null){ + + /** @type {LayerModel} */ + const self = this; + + /** @type {RoutesMaker} */ + this.routes_maker = routes_maker; + /** @type {string} */ + this.name = name; + /** @type {string} */ + this.key = key; + /** @type {Object.} */ + this.items = {}; + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + data && self.add(data, callback); + }; + + /** + * @param {!string} name + * @param {!string} data + * @param {!layer_model_add_callback} callback + * @returns {void} + * @access public + */ + this.add = (data, callback) => { + routes_maker.input_text("What name will overlay have?", name => { + + const key = Utils.to_key(name); + + if(self.items[key]) + routes_maker.alert("The name '" + name + "' has the key '" + key + "', and this key already exists."); + else{ + + const points = []; + let event = routes_maker.map.on_click.add((_, longitude, latitude) => { + points.push(new CoordenatesModel(longitude, latitude)); + console.log(points); + if(points.length == 2){ + routes_maker.map.on_click.remove(event); + routes_maker.map.create_points = true; + self.items[key] = new LayerItemModel(self, name, key, LayerModel.clean_svg(data.content), ...points); + + // console.log(LayerModel.clean_svg(data.content)); + + // const uri_data = "data:image/svg+xml;utf-8," + encodeURIComponent(LayerModel.clean_svg(data.content)); + + }; + }); + + routes_maker.map.create_points = false; + + }; + }); + + // console.log(data); + // LayerModel.clean_svg(data.content); + }; + + this.get_distance = () => { + return 0; + }; + + constructor(); + + }; + + LayerModel.clean_svg = svg => { + return [ + // [/<\!\-{2}(?:(?:(?!(\-{2}>)).)+)(?:\-{2}>|$)/g, ""], + // [/\s+xmlns\:(?:inkscape|sodipodi)="[^"]+"/gi, ""], + // [/(\s)inkscape\:label(="[^"]+")/gi, "$1data-name$2"], + // [/\s+(?:inkscape|sodipodi)\:[^=]+="[^"]+"/gi, ""], + // [/<\/?sodipodi(\:[^\s>]+)(?:(?!>)(?:.|[\r\n]+))+>/gi, ""], + // [/>(?:\s+|[\r\n]+)+<"], + // [/[\r\n]+\s+/g, " "] + ].reduce((svg, [pattern, response]) => { + return svg.replace(pattern, response); + }, svg.trim()); + }; + + return LayerModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/RouteModel.ecma.js b/Public/ecma/Models/RouteModel.ecma.js index 1a026ab..3a16f14 100644 --- a/Public/ecma/Models/RouteModel.ecma.js +++ b/Public/ecma/Models/RouteModel.ecma.js @@ -55,17 +55,9 @@ export const RouteModel = (function(){ this.get_distance = (...slice) => ( slice.length ? self.dots.slice(...slice) : self.dots - ).reduce((distance, dot) => distance + dot.distance); + ).reduce((distance, dot) => distance + dot.distance, 0); }; - /** - * @param {!string} name - * @returns {string} - * @access public - * @static - */ - RouteModel.to_key = name => Check.is_string(name) && (name = name.trim()) ? name.replace(/_/g, "-").toLowerCase() : null; - return RouteModel; })(); \ No newline at end of file diff --git a/Public/ecma/Utils/Utils.ecma.js b/Public/ecma/Utils/Utils.ecma.js index b145919..917651f 100644 --- a/Public/ecma/Utils/Utils.ecma.js +++ b/Public/ecma/Utils/Utils.ecma.js @@ -168,21 +168,21 @@ export const Utils = (function(){ return _default; }; - Utils.download = (data, mime = "application/octet-stream") => { + Utils.download = (data, mime = "application/octet-stream", name = null) => { console.log(data); const anchor = document.createElement("a"), date = new Date(); Utils.set_attributes(anchor, { - download : "RoutesMaker." + ( - ("0000" + date.getFullYear()).slice(4) + - ("00" + (date.getMonth() + 1)).slice(2) + - ("00" + (date.getDate() + 1)).slice(2) + - ("00" + (date.getHours() + 1)).slice(2) + - ("00" + (date.getMinutes() + 1)).slice(2) + - ("00" + (date.getSeconds() + 1)).slice(2) - ) + ".json", + download : name || ("RoutesMaker." + ( + ("0000" + date.getFullYear()).slice(-4) + + ("00" + (date.getMonth() + 1)).slice(-2) + + ("00" + date.getDate()).slice(-2) + + ("00" + date.getHours()).slice(-2) + + ("00" + date.getMinutes()).slice(-2) + + ("00" + date.getSeconds()).slice(-2) + ) + ".json"), href : "data:" + mime + ";base64," + btoa(Check.is_string(data) ? data : JSON.stringify(data)), target : "_blank" }); @@ -234,5 +234,15 @@ export const Utils = (function(){ }; + Utils.to_kebab = snake => snake.replace(/_/g, "-"); + + /** + * @param {?string} item + * @returns {string|null} + * @access public + * @static + */ + Utils.to_key = item => Check.is_string(item) && (item = item.trim()) ? item.replace(/[^a-z0-9]+/ig, "_") : null; + return Utils; })(); \ No newline at end of file diff --git a/Public/ecma/Views/MapView.ecma.js b/Public/ecma/Views/MapView.ecma.js index 83c92a6..8add083 100644 --- a/Public/ecma/Views/MapView.ecma.js +++ b/Public/ecma/Views/MapView.ecma.js @@ -35,8 +35,12 @@ export const MapView = (function(){ /** @type {Array.<[number, number]>} */ dots = []; + this.create_points = true; + /** @type {EventModel} */ this.on_dots_change = new EventModel(); + /** @type {EventModel} */ + this.on_click = new EventModel(); /** @type {MapDriverInterface} */ this.driver = null; @@ -44,16 +48,19 @@ export const MapView = (function(){ const constructor = () => {}; this.set_point = (longitude, latitude) => { + if(self.create_points){ - const route_key = routes_maker.menu.get_route_selected(); + const [key, type] = routes_maker.menu.get_selected(); - if(route_key){ - routes_maker.routes.get(route_key).add_dot(longitude, latitude).on_change.add((..._) => { + if(key){ + routes_maker[type].get(key).add_dot(longitude, latitude).on_change.add((..._) => { + recalculate_total_distance(); + }); recalculate_total_distance(); - }); - recalculate_total_distance(); - }; + }; + }; + self.on_click.execute(longitude, latitude); }; this.build = () => { @@ -94,10 +101,10 @@ export const MapView = (function(){ const recalculate_total_distance = () => { - const route_key = routes_maker.menu.get_route_selected(); + const [key, type] = routes_maker.menu.get_selected()[0]; - route_key && - (routes_maker.base.item.querySelector(".map-menu [name=distance]").value = routes_maker.routes.get(route_key).get_distance() >> 0); + key && + (routes_maker.base.item.querySelector(".map-menu [name=distance]").value = routes_maker[type].get(key).get_distance() >> 0); }; diff --git a/Public/ecma/Views/MenuView.ecma.js b/Public/ecma/Views/MenuView.ecma.js index 5b64d9b..fb5b70e 100644 --- a/Public/ecma/Views/MenuView.ecma.js +++ b/Public/ecma/Views/MenuView.ecma.js @@ -1,5 +1,6 @@ "use strict"; +import { CoordenatesModel } from "../Models/CoordenatesModel.ecma.js"; import {Utils} from "../Utils/Utils.ecma.js"; /** @@ -64,6 +65,9 @@ export const MenuView = (function(){ data_selected : true, title : object.name }, [ + MenuView.toggle_button("visible", (button, event, on) => { + routes_maker.routes.visible(button.parentNode.getAttribute("data-key"), on); + }, "Visible", true), ["span", { class : "name", on_click : (item, event) => { @@ -74,12 +78,20 @@ export const MenuView = (function(){ ], routes_maker.base.item)[0]); }; + const get_new_name = () => routes_maker.base.item.querySelector(".map-menu [name=item_name]").value.trim(); + const add_new_route = (item, event) => { - add_new_item(routes_maker.routes.add(item.parentNode.querySelector("[type=text]").value.trim()), "routes"); + add_new_item(routes_maker.routes.add(get_new_name()), "routes"); }; const add_new_layer = (item, event) => { - add_new_item(null, "layers"); + + const name = get_new_name().trim(); + + name && Utils.upload((...files) => { + add_new_item(routes_maker.layers.add(name, files[0]), "layers"); + }); + }; const select_item = item => { @@ -87,6 +99,8 @@ export const MenuView = (function(){ item.setAttribute("data-selected", false); }); item.setAttribute("data-selected", true); + routes_maker.routes.select(self.get_selected()[0]); + self.recalculate_total_distance(); }; const clear_item_name = (item, event) => { @@ -163,12 +177,24 @@ export const MenuView = (function(){ * @returns {string|null} * @access public */ - this.get_route_selected = () => { + this.get_selected = () => { /** @type {HTMLLIElement|null} */ const item_selected = routes_maker.base.item.querySelector(".map-menu [data-field=items] [data-selected=true]"); - return item_selected ? item_selected.getAttribute("data-key") : null; + return item_selected ? [ + item_selected.getAttribute("data-key"), + item_selected.getAttribute("data-type") + ] : [null, null]; + }; + + this.recalculate_total_distance = () => { + + const [key, type] = self.get_selected(); + + key && + (routes_maker.base.item.querySelector(".map-menu [name=distance]").value = routes_maker[type].get(key).get_distance() >> 0); + }; constructor(); @@ -260,7 +286,22 @@ export const MenuView = (function(){ }, [ ["span", {data_icon : name}], ["span", {data_i18n : name}, text] - ]]], text) + ]]], text); + + MenuView.toggle_button = (name, action, text, on = true) => ["button", { + type : "button", + data_i18n : name, + data_i18n_without : true, + title : text, + data_toggle : on, + on_click : (button, event, on = null) => { + button.setAttribute("data-toggle", on !== null ? on : on = button.getAttribute("data-toggle") != "true"); + action(button, event, on); + } + }, [ + ["span", {data_icon : name}], + ["span", {data_i18n : name}, text] + ]] return MenuView; })(); \ No newline at end of file diff --git a/Public/scss/RoutesMaker.css b/Public/scss/RoutesMaker.css index 60517d4..bf4b6c6 100644 --- a/Public/scss/RoutesMaker.css +++ b/Public/scss/RoutesMaker.css @@ -15,6 +15,10 @@ left: 1em; width: 20em; z-index: 20; } + .routes-maker .leaflet-container [data-visible=false] { + display: none; } + .routes-maker .leaflet-container [data-selected=false] { + opacity: .5; } .routes-maker [data-show-markers=false] .leaflet-marker-pane, .routes-maker [data-show-markers=false] .leaflet-shadow-pane { display: none; } .routes-maker [data-show-routes=false] .leaflet-overlay-pane { diff --git a/Public/scss/RoutesMaker.css.map b/Public/scss/RoutesMaker.css.map index faff417..2463be5 100644 --- a/Public/scss/RoutesMaker.css.map +++ b/Public/scss/RoutesMaker.css.map @@ -1,6 +1,6 @@ { "version": 3, -"mappings": "AAAA,aAAa;EAET,QAAQ,EAAG,QAAQ;EACnB,oBAAM;IAAC,QAAQ,EAAG,QAAQ;EAC1B,mCAAQ;IACJ,GAAG,EAAG,GAAG;IACT,IAAI,EAAG,GAAG;IACV,KAAK,EAAG,IAAI;IACZ,MAAM,EAAG,IAAI;IACb,QAAQ,EAAG,MAAM;IACjB,OAAO,EAAG,EAAE;EAGhB,yBAAW;IACP,QAAQ,EAAG,QAAQ;IACnB,GAAG,EAAG,GAAG;IACT,IAAI,EAAG,GAAG;IACV,KAAK,EAAG,IAAI;IACZ,OAAO,EAAG,EAAE;EAGU,0HAAyC;IAAC,OAAO,EAAG,IAAI;EAClF,4DAA8C;IAAC,OAAO,EAAG,IAAI", +"mappings": "AAAA,aAAa;EAET,QAAQ,EAAG,QAAQ;EACnB,oBAAM;IAAC,QAAQ,EAAG,QAAQ;EAC1B,mCAAQ;IACJ,GAAG,EAAG,GAAG;IACT,IAAI,EAAG,GAAG;IACV,KAAK,EAAG,IAAI;IACZ,MAAM,EAAG,IAAI;IACb,QAAQ,EAAG,MAAM;IACjB,OAAO,EAAG,EAAE;EAGhB,yBAAW;IACP,QAAQ,EAAG,QAAQ;IACnB,GAAG,EAAG,GAAG;IACT,IAAI,EAAG,GAAG;IACV,KAAK,EAAG,IAAI;IACZ,OAAO,EAAG,EAAE;EAIZ,qDAAoB;IAAC,OAAO,EAAG,IAAI;EACnC,sDAAqB;IAAC,OAAO,EAAG,EAAE;EAGZ,0HAAyC;IAAC,OAAO,EAAG,IAAI;EAClF,4DAA8C;IAAC,OAAO,EAAG,IAAI", "sources": ["RoutesMaker.scss"], "names": [], "file": "RoutesMaker.css" diff --git a/Public/scss/RoutesMaker.scss b/Public/scss/RoutesMaker.scss index 79b0562..6109bfc 100644 --- a/Public/scss/RoutesMaker.scss +++ b/Public/scss/RoutesMaker.scss @@ -19,6 +19,11 @@ z-index : 20; } + .leaflet-container{ + [data-visible=false]{display : none;} + [data-selected=false]{opacity : .5;} + } + [data-show-markers=false]{.leaflet-marker-pane,.leaflet-shadow-pane{display : none;}} [data-show-routes=false] .leaflet-overlay-pane{display : none;}