#wip(ecma): SVG XML Overlays exists.

This commit is contained in:
KyMAN 2025-07-07 07:46:10 +02:00
parent 8155e40a95
commit 0a3faa5893
15 changed files with 663 additions and 111 deletions

View File

@ -7,6 +7,7 @@ import {MenuView} from "../Views/MenuView.ecma.js";
import {MapView} from "../Views/MapView.ecma.js"; import {MapView} from "../Views/MapView.ecma.js";
import {RoutesManager} from "../Managers/RoutesManager.ecma.js"; import {RoutesManager} from "../Managers/RoutesManager.ecma.js";
import {RandomKeysManager} from "../Managers/RandomKeysManager.ecma.js"; import {RandomKeysManager} from "../Managers/RandomKeysManager.ecma.js";
import {LayersManager} from "../Managers/LayersManager.ecma.js";
/** /**
* @callback routes_maker_ready_callback * @callback routes_maker_ready_callback
@ -42,9 +43,6 @@ export const RoutesMaker = (function(){
/** @type {number} */ /** @type {number} */
longitude = 0; longitude = 0;
/** @type {HTMLElement|null} */
this.item_self = null;
/** @type {EventModel} */ /** @type {EventModel} */
this.on_ready = new EventModel(); this.on_ready = new EventModel();
@ -58,6 +56,8 @@ export const RoutesMaker = (function(){
this.random_keys = new RandomKeysManager(); this.random_keys = new RandomKeysManager();
/** @type {RoutesManager} */ /** @type {RoutesManager} */
this.routes = new RoutesManager(self); this.routes = new RoutesManager(self);
/** @type {LayersManager} */
this.layers = new LayersManager(self);
const constructor = () => { const constructor = () => {
self.on_ready.add(callback); self.on_ready.add(callback);
@ -96,6 +96,19 @@ export const RoutesMaker = (function(){
*/ */
this.get_user_coordenates = () => [latitude, longitude]; 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(); constructor();
}; };

View File

@ -2,6 +2,7 @@
import {MapDriverInterface} from "../Interfaces/MapDriverInterface.ecma.js"; import {MapDriverInterface} from "../Interfaces/MapDriverInterface.ecma.js";
import {EventModel} from "../Models/EventModel.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("../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 * @param {!DotModel} dot
* @returns {void} * @returns {void}
* @access public * @access public
*/ */
this.add_dot = dot => { this.add_dot = (dot, attributes = {}) => {
/** @type {[number, number]} */ /** @type {[number, number]} */
const point = dot.get_point(); const point = dot.get_point();
@ -100,6 +131,7 @@ export const LeafLetOSMDriver = (function(){
dot.on_drop.execute(coordenates.lng, coordenates.lat); 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; next = dot.i + 1 < dot.route.dots.length ? dot.route.dots[dot.i + 1] : null;
self.remove_dot_lines(dot); self.remove_dot_lines(dot);
previous && (dot.line = L.polyline([previous.get_point(), point])).addTo(self.map); if(previous){
next && (next.line = L.polyline([point, next.get_point()])).addTo(self.map); (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); 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(); constructor();
}; };

View File

@ -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;
})();

View File

@ -1,36 +1,109 @@
"use strict"; "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(){ export const RoutesManager = (function(){
/**
* @constructs RoutesManager
* @param {!RoutesMaker} routes_maker
* @returns {void}
* @access public
* @static
*/
const RoutesManager = function(routes_maker){ const RoutesManager = function(routes_maker){
/** @type {Object.<string, RouteModel>} */
const routes = {}; 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) => { this.add = (name, key = null) => {
/** @type {RouteModel|null} */
let route = null; let route = null;
(key || (key = RouteModel.to_key(name))) && (key || (key = Utils.to_key(name))) &&
!routes[key] && !routes[key] &&
(route = routes[key] = new RouteModel(routes_maker, name, key)); (route = routes[key] = new RouteModel(routes_maker, name, key));
return route; return route;
}; };
/**
* @param {!string} key
* @returns {void}
* @access public
*/
this.remove = key => { this.remove = key => {
if(routes[key = RouteModel.to_key(key)]) if(routes[key = Utils.to_key(key)])
delete routes[key]; delete routes[key];
}; };
/**
* @returns {Object.<string, any>}
* @access public
*/
this.get_data = () => Object.keys(routes).reduce((dictionary, key) => { this.get_data = () => Object.keys(routes).reduce((dictionary, key) => {
dictionary[key] = [routes[key].name, routes[key].dots.map(dot => [dot.longitude, dot.latitude])]; dictionary[key] = [routes[key].name, routes[key].dots.map(dot => [dot.longitude, dot.latitude])];
return dictionary; 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; return RoutesManager;

View File

@ -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;
})();

View File

@ -51,6 +51,14 @@ export const DotModel = (function(){
/** @type {number} */ /** @type {number} */
this.distance = 0; this.distance = 0;
/** @type {object.<string, any|null>} */
this.attributes = {
/** @type {boolean} */
visible : true,
/** @type {boolean} */
selected : true
};
/** @type {EventModel} */ /** @type {EventModel} */
this.on_change = new EventModel(); this.on_change = new EventModel();
/** @type {EventModel} */ /** @type {EventModel} */
@ -74,35 +82,6 @@ export const DotModel = (function(){
self.recalculate_distance(); self.recalculate_distance();
}); });
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]; 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} * @returns {void}
* @access public * @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.routes_maker.map.driver.redraw_dot_lines(route.dots[self.i]);
not_unique && route.dots[self.i].recalculate_distance(); 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(); constructor();
}; };

View File

@ -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.<string, any|null>} */
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;
})();

View File

@ -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.<string, LayerItemModel>} */
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]+)+</g, "><"],
// [/[\r\n]+\s+/g, " "]
].reduce((svg, [pattern, response]) => {
return svg.replace(pattern, response);
}, svg.trim());
};
return LayerModel;
})();

View File

@ -55,17 +55,9 @@ export const RouteModel = (function(){
this.get_distance = (...slice) => ( this.get_distance = (...slice) => (
slice.length ? self.dots.slice(...slice) : self.dots 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; return RouteModel;
})(); })();

View File

@ -168,21 +168,21 @@ export const Utils = (function(){
return _default; return _default;
}; };
Utils.download = (data, mime = "application/octet-stream") => { Utils.download = (data, mime = "application/octet-stream", name = null) => {
console.log(data); console.log(data);
const anchor = document.createElement("a"), const anchor = document.createElement("a"),
date = new Date(); date = new Date();
Utils.set_attributes(anchor, { Utils.set_attributes(anchor, {
download : "RoutesMaker." + ( download : name || ("RoutesMaker." + (
("0000" + date.getFullYear()).slice(4) + ("0000" + date.getFullYear()).slice(-4) +
("00" + (date.getMonth() + 1)).slice(2) + ("00" + (date.getMonth() + 1)).slice(-2) +
("00" + (date.getDate() + 1)).slice(2) + ("00" + date.getDate()).slice(-2) +
("00" + (date.getHours() + 1)).slice(2) + ("00" + date.getHours()).slice(-2) +
("00" + (date.getMinutes() + 1)).slice(2) + ("00" + date.getMinutes()).slice(-2) +
("00" + (date.getSeconds() + 1)).slice(2) ("00" + date.getSeconds()).slice(-2)
) + ".json", ) + ".json"),
href : "data:" + mime + ";base64," + btoa(Check.is_string(data) ? data : JSON.stringify(data)), href : "data:" + mime + ";base64," + btoa(Check.is_string(data) ? data : JSON.stringify(data)),
target : "_blank" 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; return Utils;
})(); })();

View File

@ -35,8 +35,12 @@ export const MapView = (function(){
/** @type {Array.<[number, number]>} */ /** @type {Array.<[number, number]>} */
dots = []; dots = [];
this.create_points = true;
/** @type {EventModel} */ /** @type {EventModel} */
this.on_dots_change = new EventModel(); this.on_dots_change = new EventModel();
/** @type {EventModel} */
this.on_click = new EventModel();
/** @type {MapDriverInterface} */ /** @type {MapDriverInterface} */
this.driver = null; this.driver = null;
@ -44,16 +48,19 @@ export const MapView = (function(){
const constructor = () => {}; const constructor = () => {};
this.set_point = (longitude, latitude) => { 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){ if(key){
routes_maker.routes.get(route_key).add_dot(longitude, latitude).on_change.add((..._) => { routes_maker[type].get(key).add_dot(longitude, latitude).on_change.add((..._) => {
recalculate_total_distance();
});
recalculate_total_distance(); recalculate_total_distance();
}); };
recalculate_total_distance();
};
};
self.on_click.execute(longitude, latitude);
}; };
this.build = () => { this.build = () => {
@ -94,10 +101,10 @@ export const MapView = (function(){
const recalculate_total_distance = () => { const recalculate_total_distance = () => {
const route_key = routes_maker.menu.get_route_selected(); const [key, type] = routes_maker.menu.get_selected()[0];
route_key && key &&
(routes_maker.base.item.querySelector(".map-menu [name=distance]").value = routes_maker.routes.get(route_key).get_distance() >> 0); (routes_maker.base.item.querySelector(".map-menu [name=distance]").value = routes_maker[type].get(key).get_distance() >> 0);
}; };

View File

@ -1,5 +1,6 @@
"use strict"; "use strict";
import { CoordenatesModel } from "../Models/CoordenatesModel.ecma.js";
import {Utils} from "../Utils/Utils.ecma.js"; import {Utils} from "../Utils/Utils.ecma.js";
/** /**
@ -64,6 +65,9 @@ export const MenuView = (function(){
data_selected : true, data_selected : true,
title : object.name title : object.name
}, [ }, [
MenuView.toggle_button("visible", (button, event, on) => {
routes_maker.routes.visible(button.parentNode.getAttribute("data-key"), on);
}, "Visible", true),
["span", { ["span", {
class : "name", class : "name",
on_click : (item, event) => { on_click : (item, event) => {
@ -74,12 +78,20 @@ export const MenuView = (function(){
], routes_maker.base.item)[0]); ], 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) => { 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) => { 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 => { const select_item = item => {
@ -87,6 +99,8 @@ export const MenuView = (function(){
item.setAttribute("data-selected", false); item.setAttribute("data-selected", false);
}); });
item.setAttribute("data-selected", true); item.setAttribute("data-selected", true);
routes_maker.routes.select(self.get_selected()[0]);
self.recalculate_total_distance();
}; };
const clear_item_name = (item, event) => { const clear_item_name = (item, event) => {
@ -163,12 +177,24 @@ export const MenuView = (function(){
* @returns {string|null} * @returns {string|null}
* @access public * @access public
*/ */
this.get_route_selected = () => { this.get_selected = () => {
/** @type {HTMLLIElement|null} */ /** @type {HTMLLIElement|null} */
const item_selected = routes_maker.base.item.querySelector(".map-menu [data-field=items] [data-selected=true]"); 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(); constructor();
@ -260,7 +286,22 @@ export const MenuView = (function(){
}, [ }, [
["span", {data_icon : name}], ["span", {data_icon : name}],
["span", {data_i18n : name}, text] ["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; return MenuView;
})(); })();

View File

@ -15,6 +15,10 @@
left: 1em; left: 1em;
width: 20em; width: 20em;
z-index: 20; } 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 { .routes-maker [data-show-markers=false] .leaflet-marker-pane, .routes-maker [data-show-markers=false] .leaflet-shadow-pane {
display: none; } display: none; }
.routes-maker [data-show-routes=false] .leaflet-overlay-pane { .routes-maker [data-show-routes=false] .leaflet-overlay-pane {

View File

@ -1,6 +1,6 @@
{ {
"version": 3, "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"], "sources": ["RoutesMaker.scss"],
"names": [], "names": [],
"file": "RoutesMaker.css" "file": "RoutesMaker.css"

View File

@ -19,6 +19,11 @@
z-index : 20; 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-markers=false]{.leaflet-marker-pane,.leaflet-shadow-pane{display : none;}}
[data-show-routes=false] .leaflet-overlay-pane{display : none;} [data-show-routes=false] .leaflet-overlay-pane{display : none;}