diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cfe8847 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/Data +/Public/data +.sass-cache +*.[Ss]ecrets.* \ No newline at end of file diff --git a/Public/ecma/Application/RoutesMaker.ecma.js b/Public/ecma/Application/RoutesMaker.ecma.js new file mode 100644 index 0000000..13c9ce7 --- /dev/null +++ b/Public/ecma/Application/RoutesMaker.ecma.js @@ -0,0 +1,98 @@ +"use strict"; + +import {Utils} from "../Utils/Utils.ecma.js"; +import {EventModel} from "../Models/EventModel.ecma.js"; +import {BaseView} from "../Views/BaseView.ecma.js"; +import {MenuView} from "../Views/MenuView.ecma.js"; +import {MapView} from "../Views/MapView.ecma.js"; + +/** + * @callback routes_maker_ready_callback + * @param {!RoutesMaker} routes_maker + * @returns {void} + */ + +/** + * @class + * @constructor + * @param {!(string|HTMLElement)} [position = "body"] + * @param {?routes_maker_ready_callback} [callback = null] + * @returns {void} + * @access public + * @static + */ +export const RoutesMaker = (function(){ + + /** + * @constructs RoutesMaker + * @param {!(string|HTMLElement)} [position = "body"] + * @param {?routes_maker_ready_callback} [callback = null] + * @returns {void} + * @access private + * @static + */ + const RoutesMaker = function(position = "body", callback = null){ + + /** @type {RoutesMaker} */ + const self = this; + /** @type {number} */ + let latitude = 0, + /** @type {number} */ + longitude = 0; + + /** @type {HTMLElement|null} */ + this.item_self = null; + + /** @type {EventModel} */ + this.on_ready = new EventModel(); + + /** @type {BaseView} */ + this.base = new BaseView(self); + /** @type {MenuView} */ + this.menu = new MenuView(self); + /** @type {MapView} */ + this.map = new MapView(self); + + const constructor = () => { + self.on_ready.add(callback); + navigator.geolocation.getCurrentPosition(location => { + longitude = location.coords.longitude; + latitude = location.coords.latitude; + build(); + }, () => { + build(); + }); + }; + + /** + * @returns {void} + * @access private + */ + const build = () => { + Utils.preload(position, (position, asynchronous, ok) => { + if(ok){ + try{ + self.base.build(position); + self.map.build(); + self.menu.build(); + self.on_ready.autoexecute = true; + self.on_ready.execute(self); + }catch(exception){ + console.error(exception); + }; + }; + }); + }; + + /** + * @returns {[number, number]} + * @access public + */ + this.get_user_coordenates = () => [latitude, longitude]; + + constructor(); + + }; + + return RoutesMaker; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/DotModel.ecma.js b/Public/ecma/Models/DotModel.ecma.js new file mode 100644 index 0000000..6181a0a --- /dev/null +++ b/Public/ecma/Models/DotModel.ecma.js @@ -0,0 +1,199 @@ +"use strict"; + +import {EventModel} from "./EventModel.ecma.js"; + +/** + * @class + * @constructor + * @param {!L.Map} map + * @param {!number} x + * @param {!number} y + * @param {!number} i + * @param {!Array.} dots + * @returns {void} + * @access public + * @statix + */ +export const DotModel = (function(){ + + /** + * @constructs DotModel + * @param {!L.Map} map + * @param {!number} x + * @param {!number} y + * @param {!number} i + * @param {!Array.} dots + * @returns {void} + * @access private + * @statix + */ + const DotModel = function(map, x, y, i, dots){ + + /** @type {DotModel} */ + const self = this; + + /** @type {Array.} */ + this.map = map; + /** @type {number} */ + this.i = i; + /** @type {number} */ + this.x = x; + /** @type {number} */ + this.y = y; + /** @type {L.Marker} */ + this.marker = L.marker([y, x], {draggable : true}); + /** @type {L.Pulyline|null} */ + this.line = null; + /** @type {Array.} */ + this.dots = dots; + /** @type {number} */ + this.distance = 0; + + /** @type {EventModel} */ + this.on_change = new EventModel(); + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + 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.x = coordenates.lng; + self.y = 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(); + }; + + /** + * @returns {Object.} + * @access public + */ + this.get_leaflet_coordenates = () => ({ + lat : self.y, + lng : self.x + }); + + /** + * @returns {Object.} + * @access public + */ + this.get_coordenates = () => ({ + latitude : self.y, + longitude : self.x + }); + + /** + * @returns {[string, number]} + * @access public + */ + this.get_dot = () => [self.y, self.x]; + + /** + * @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 + */ + this.remove = () => { + 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 --; + }); + }; + + /** + * @returns {void} + * @access public + */ + this.recalculate_distance = () => { + + /** @type {number} */ + const origin = self.distance || 0; + + if(self.i){ + + /** @type {DotModel} */ + const previous = self.dots[self.i - 1], + /** @type {number} */ + pi_radians = Math.PI / 180, + /** @type {number} */ + angle = ( + Math.sin((self.y - previous.y) * pi_radians / 2) ** 2 + + Math.cos(self.y * pi_radians) * Math.cos(previous.y * pi_radians) * + Math.sin((self.x - previous.x) * pi_radians / 2) ** 2 + ); + + self.distance = DotModel.EARTH_RADIUS * 2 * Math.atan2(angle ** .5, (1 - angle) ** .5); + + }else + self.distance = 0; + + origin != self.distance && self.on_change.execute(self); + + }; + + constructor(); + + }; + + /** @type {number} */ + DotModel.EARTH_RADIUS = 6371000; + + return DotModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/EventModel.ecma.js b/Public/ecma/Models/EventModel.ecma.js new file mode 100644 index 0000000..d84a2e2 --- /dev/null +++ b/Public/ecma/Models/EventModel.ecma.js @@ -0,0 +1,87 @@ +"use strict"; + +import {Check} from "../Utils/Check.ecma.js"; +import {Utils} from "../Utils/Utils.ecma.js"; + +/** + * @callback event_model_callback + * @param {!number} i + * @param {...any} [parameters] + * @returns {Array.} + */ + +/** + * @class + * @constructor + * @returns {void} + * @access public + * @static + */ +export const EventModel = (function(){ + + /** + * @constructs EventModel + * @returns {void} + * @access private + * @static + */ + const EventModel = function(){ + + /** @type {EventModel} */ + const self = this, + /** @type {Array.} */ + events = []; + + /** @type {boolean} */ + this.autoexecute = false; + + /** + * @param {...any} [parameters] + * @returns {Array.} + * @access public + */ + this.execute = (...parameters) => events.map((event, i) => event ? event(i, ...parameters) : null); + + /** + * @param {!event_model_callback} callback + * @returns {number|null} + * @access public + */ + this.add = callback => { + + /** @type {number|null} */ + let i = null; + + if(Check.is_function(callback)){ + if(self.autoexecute) + Utils.execute(callback); + else{ + + /** @type {number} */ + const l = events.length; + + for(i = 0; i < l; i ++) + if(!events[i]) + break; + + events[i] = callback; + + }; + }; + + return i; + }; + + /** + * @param {!number} i + * @returns {void} + * @access public + */ + this.remove = i => { + Check.is_index(i) && i < events.length && events[i] && (events[i] = null); + }; + + }; + + return EventModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Models/ScreenModel.ecma.js b/Public/ecma/Models/ScreenModel.ecma.js new file mode 100644 index 0000000..57ef068 --- /dev/null +++ b/Public/ecma/Models/ScreenModel.ecma.js @@ -0,0 +1,65 @@ +"use strict"; + +import {EventModel} from "./EventModel.ecma.js"; +import {Utils} from "../Utils/Utils.ecma.js"; + +/** + * @class + * @constructor + * @param {!(string|HTMLElement)} selector + * @returns {void} + * @access public + * @static + */ +export const ScreenModel = (function(){ + + /** + * @constructs ScreenModel + * @param {!(string|HTMLElement)} selector + * @returns {void} + * @access private + * @static + */ + const ScreenModel = function(selector){ + + /** @type {ScreenModel} */ + const self = this; + + /** @type {number|null} */ + let interval = null; + + /** @type {number} */ + this.x = 0; + /** @type {number} */ + this.y = 0; + /** @type {HTMLElement|null} */ + this.item = null; + + /** @type {EventModel} */ + this.on_change = new EventModel(); + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + Utils.preload(selector, (item, asynchronous, ok) => { + if(ok){ + self.item = item; + interval = setInterval(() => { + if(self.x != self.item.offsetWidth || self.y != self.item.offsetHeight){ + self.x = self.item.offsetWidth; + self.y = self.item.offsetHeight; + this.on_change.execute(self.x, self.y, self.item); + }; + }, 100); + }; + }); + }; + + constructor(); + + }; + + return ScreenModel; +})(); \ No newline at end of file diff --git a/Public/ecma/Utils/Check.ecma.js b/Public/ecma/Utils/Check.ecma.js new file mode 100644 index 0000000..2d00560 --- /dev/null +++ b/Public/ecma/Utils/Check.ecma.js @@ -0,0 +1,85 @@ +"use strict"; + +/** + * @class + * @constructor + * @returns {void} + * @access public + * @static + */ +export const Check = (function(){ + + /** + * @constructs Check + * @returns {void} + * @access private + * @static + */ + const Check = function(){}; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_function = item => typeof item == "function"; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_number = item => typeof item == "number"; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_integer = item => Check.is_number(item) && item == item >> 0; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_index = item => Check.is_integer(item) && item >= 0; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_html_object = item => item && item.constructor == Object; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_string = item => typeof item == "string"; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_null_or_undefined = item => item === undefined || item === null; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Check.is_array = item => item instanceof Array; + + return Check; +})(); \ No newline at end of file diff --git a/Public/ecma/Utils/Utils.ecma.js b/Public/ecma/Utils/Utils.ecma.js new file mode 100644 index 0000000..643dee5 --- /dev/null +++ b/Public/ecma/Utils/Utils.ecma.js @@ -0,0 +1,145 @@ +"use strict"; + +import {Check} from "./Check.ecma.js"; + +/** + * @callback utils_preload_callback + * @param {?HTMLElement} item + * @param {!boolean} asynchronous + * @param {!boolean} ok + * @returns {void} + */ + +/** + * @callback utils_execute_callback + * @param {...any} [paramenters] + * @returns {any|null} + */ + +/** + * @class + * @constructor + * @returns {void} + * @access public + * @static + */ +export const Utils = (function(){ + + /** + * @constructs Utils + * @returns {void} + * @access private + * @static + */ + const Utils = function(){}; + + /** + * @param {!(string|HTMLElement)} selector + * @param {!utils_preload_callback} callback + * @param {!(Document|HTMLElement)} [root = document] + * @param {!number} [timeout = 2000] + * @returns {void} + * @access public + * @static + */ + Utils.preload = (selector, callback, root = document, timeout = 2000) => { + if(!selector) + callback(null, false, false); + else if(Check.is_html_object(selector)) + callback(selector, false, true); + else if(Check.is_string(selector) && (selector = selector.trim())){ + + /** @type {HTMLElement|null} */ + let item = null; + + try{ + if(item = root.querySelector(selector)){ + callback(item, false, true); + return; + }; + }catch(exception){ + callback(null, false, false); + return; + }; + + /** @type {number} */ + const date = Date.now(); + /** @type {number} */ + let interval = setInterval(() => { + if(item = root.querySelector(selector)){ + clearInterval(interval); + callback(item, true, true); + }else if(Date.now() - date > timeout){ + clearInterval(interval); + callback(null, false, true); + }; + }, 100); + + }else + callback(null, false, false); + }; + + /** + * @param {!utils_execute_callback} callback + * @param {...any} [parameters] + * @returns {any|null} + * @access public + * @static + */ + Utils.execute = (callback, ...parameters) => Check.is_function(callback) ? callback(...parameters) : null; + + /** + * @param {!(string|HTMLElement)} selector + * @param {!Object.} attributes + * @param {!(HTMLElement|Document)} [position = document] + * @returns {void} + * @access public + * @static + */ + Utils.set_attributes = (selector, attributes, position = document) => { + (Check.is_string(selector) ? position.querySelectorAll(selector) : [selector]).forEach(item => { + for(const key in attributes){ + if(/^on_?/i.test(key)) + item.addEventListener( + key.substring(2).replace(/[^a-z]+/g, "").toLowerCase(), + event => Utils.execute(attributes[key], item, event) + ); + else + item.setAttribute(key.replace(/_|([A-Z])/g, (_, character) => { + return character ? "-" + character.toLowerCase() : "-"; + }), attributes[key]); + }; + }); + }; + + /** + * @param {!(string|HTMLElement|Document)} selector + * @param {!Array.<[string, Object.|null, Array.|null]} items + * @param {!(HTMLElement|Document)} [position = document] + * @returns {Array.} + * @access public + * @static + */ + Utils.set_html = (selector, items, position = document) => { + + Check.is_string(selector) && (selector = position.querySelector(selector)); + + return items.map(([tag, attributes, childs]) => { + + /** @type {HTMLElement} */ + const item = selector.appendChild(document.createElement(tag)); + + attributes && Utils.set_attributes(item, attributes); + if(!Check.is_null_or_undefined(childs)){ + if(Check.is_string(childs)) + item.innerHTML = childs; + else if(Check.is_array(childs)) + Utils.set_html(item, childs); + }; + + return item; + }); + }; + + return Utils; +})(); \ No newline at end of file diff --git a/Public/ecma/Views/BaseView.ecma.js b/Public/ecma/Views/BaseView.ecma.js new file mode 100644 index 0000000..510471e --- /dev/null +++ b/Public/ecma/Views/BaseView.ecma.js @@ -0,0 +1,32 @@ +"use strict"; + +import {Utils} from "../Utils/Utils.ecma.js"; + +export const BaseView = (function(){ + + const BaseView = function(routes_marker){ + + const self = this; + + const constructor = () => {}; + + this.build = position => { + routes_marker.item_self || + (routes_marker.item_self = Utils.set_html(position, [ + ["div", { + id : "routes-maker", + class : "routes-maker", + data_application : "RoutesMaker", + data_git : "https://git.k3y.pw/KyMAN/RoutesMaker", + data_url : "https://routesmaker.k3y.pw/", + data_author : "KyMAN" + }] + ])[0]); + }; + + constructor(); + + }; + + return BaseView; +})(); \ No newline at end of file diff --git a/Public/ecma/Views/MapView.ecma.js b/Public/ecma/Views/MapView.ecma.js new file mode 100644 index 0000000..b140981 --- /dev/null +++ b/Public/ecma/Views/MapView.ecma.js @@ -0,0 +1,70 @@ +"use strict"; + +import {Utils} from "../Utils/Utils.ecma.js"; +import {EventModel} from "../Models/EventModel.ecma.js"; +import {DotModel} from "../Models/DotModel.ecma.js"; +import {ScreenModel} from "../Models/ScreenModel.ecma.js"; + +export const MapView = (function(){ + + const MapView = function(routes_marker){ + + const self = this; + let built = false, + /** @type {Array.<[number, number]>} */ + dots = []; + + /** @type {ScreenModel|null} */ + this.screen = null; + /** @type {EventModel} */ + this.on_dots_change = new EventModel(); + + /** @type {HTMLElement|null} */ + this.box = null; + /** @type {L.Map|null} */ + this.map = null; + + const constructor = () => {}; + + this.build = () => { + if(!built && routes_marker.item_self){ + built = true; + self.box = Utils.set_html(routes_marker.item_self, [ + ["div", { + id : "routes-maker-map", + class : "map", + data_show_markers : true, + data_show_routes : true + }] + ])[0]; + L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", { + maxZoom : 19, + attribution : '© OpenStreetMap' + }).addTo(self.map = L.map("routes-maker-map").setView(routes_marker.get_user_coordenates(), 13)); + (self.screen = new ScreenModel(self.box)).on_change.add((i, x, y, box) => { + self.map.invalidateSize(true); + }); + self.map.on("click", event => { + + const dot = new DotModel(self.map, event.latlng.lng, event.latlng.lat, dots.length, dots); + + dots.push(dot); + recalculate_total_distance(); + dot.on_change.add(() => { + recalculate_total_distance(); + }); + + }); + }; + }; + + const recalculate_total_distance = () => { + routes_marker.item_self.querySelector(".map-menu [name=distance]").value = dots.reduce((distance, dot) => distance + dot.distance, 0) >> 0; + }; + + constructor(); + + }; + + return MapView; +})(); \ No newline at end of file diff --git a/Public/ecma/Views/MenuView.ecma.js b/Public/ecma/Views/MenuView.ecma.js new file mode 100644 index 0000000..3cbf88d --- /dev/null +++ b/Public/ecma/Views/MenuView.ecma.js @@ -0,0 +1,99 @@ +"use strict"; + +import {Utils} from "../Utils/Utils.ecma.js"; + +export const MenuView = (function(){ + + const MenuView = function(routes_marker){ + + const self = this; + let built = false; + + const constructor = () => {}; + + this.build = () => { + if(!built && routes_marker.item_self){ + built = true; + Utils.set_html(routes_marker.item_self, [ + ["form", { + class : "map-menu", + method : "GET", + action : "#", + on_submit : (form, event) => false + }, [ + ["fieldset", null, [ + ["legend", {data_i18n : "menu"}, "Menu"], + ["nav", null, [ + ["ul", null, [ + ["li", { + data_i : 0, + data_field : "distance", + data_i18n : "distance", + data_i18n_without : true, + title : "Distance" + }, [ + ["label", {for : "distance"}, [ + ["span", {data_i18n : "distance"}, "Distance"], + ["input", { + type : "text", + name : "distance", + readonly : true, + id : "distance" + }], + ["span", {data_i18n : "meters_symbol"}, "m"] + ]] + ]], + ["li", { + data_i : 1, + data_field : "show-markers", + data_i18n : "show_markers", + data_i18n_without : true, + title : "Show markers" + }, [ + ["label", {for : "show-markers"}, [ + ["input", { + type : "checkbox", + name : "show_markers", + id : "show-markers", + checked : true, + on_change : (item, event) => { + Utils.set_attributes(".map", {data_show_markers : item.checked}, routes_marker.item_self); + } + }], + ["span", {data_i18n : "show_markers"}, "Show markers"] + ]] + ]], + ["li", { + data_i : 2, + data_field : "show-routes", + data_i18n : "show_routes", + data_i18n_without : true, + title : "Show routes" + }, [ + ["label", {for : "show-routes"}, [ + ["input", { + type : "checkbox", + name : "show_routes", + id : "show-routes", + checked : true, + on_change : (item, event) => { + Utils.set_attributes(".map", {data_show_routes : item.checked}, routes_marker.item_self); + } + }], + ["span", {data_i18n : "show_routes"}, "Show routes"] + ]] + ]] + ]] + ]] + ]] + ]] + ]); + }; + }; + + constructor(); + + }; + + return MenuView; +})(); \ No newline at end of file diff --git a/Public/index.html b/Public/index.html new file mode 100644 index 0000000..1476d17 --- /dev/null +++ b/Public/index.html @@ -0,0 +1,40 @@ + + + + RoutesMaker + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Public/scss/RoutesMaker.css b/Public/scss/RoutesMaker.css new file mode 100644 index 0000000..60517d4 --- /dev/null +++ b/Public/scss/RoutesMaker.css @@ -0,0 +1,23 @@ +.routes-maker { + position: relative; } + .routes-maker > .map { + position: absolute; } + .routes-maker, .routes-maker > .map { + top: 0em; + left: 0em; + width: 100%; + height: 100%; + overflow: hidden; + z-index: 10; } + .routes-maker > .map-menu { + position: absolute; + top: 5em; + left: 1em; + width: 20em; + z-index: 20; } + .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 { + display: none; } + +/*# sourceMappingURL=RoutesMaker.css.map */ diff --git a/Public/scss/RoutesMaker.css.map b/Public/scss/RoutesMaker.css.map new file mode 100644 index 0000000..faff417 --- /dev/null +++ b/Public/scss/RoutesMaker.css.map @@ -0,0 +1,7 @@ +{ +"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", +"sources": ["RoutesMaker.scss"], +"names": [], +"file": "RoutesMaker.css" +} diff --git a/Public/scss/RoutesMaker.scss b/Public/scss/RoutesMaker.scss new file mode 100644 index 0000000..79b0562 --- /dev/null +++ b/Public/scss/RoutesMaker.scss @@ -0,0 +1,25 @@ +.routes-maker{ + + position : relative; + &>.map{position : absolute;} + &,&>.map{ + top : 0em; + left : 0em; + width : 100%; + height : 100%; + overflow : hidden; + z-index : 10; + } + + &>.map-menu{ + position : absolute; + top : 5em; + left : 1em; + width : 20em; + z-index : 20; + } + + [data-show-markers=false]{.leaflet-marker-pane,.leaflet-shadow-pane{display : none;}} + [data-show-routes=false] .leaflet-overlay-pane{display : none;} + +} \ No newline at end of file diff --git a/Tools/sass.sh b/Tools/sass.sh new file mode 100755 index 0000000..fdf59e0 --- /dev/null +++ b/Tools/sass.sh @@ -0,0 +1,3 @@ +#!/bin/bash +directory=`dirname $(readlink -f "$0")` +sass $directory/../Public/scss/RoutesMaker.scss ../Public/scss/RoutesMaker.css; \ No newline at end of file