RoutesMaker/Public/ecma/Models/DotModel.ecma.js

164 lines
4.4 KiB
JavaScript

"use strict";
import {EventModel} from "./EventModel.ecma.js";
/**
* @typedef {import("./RouteModel.ecma.js").RouteModel} RouteModel
*/
/**
* @class
* @constructor
* @param {!RouteModel} route
* @param {!number} x
* @param {!number} y
* @param {!number} i
* @param {!Array.<DotModel>} dots
* @returns {void}
* @access public
* @statix
*/
export const DotModel = (function(){
/**
* @constructs DotModel
* @param {!RouteModel} route
* @param {!number} x
* @param {!number} y
* @param {!number} i
* @param {!Array.<DotModel>} dots
* @returns {void}
* @access private
* @statix
*/
const DotModel = function(route, longitude, latitude, i){
/** @type {DotModel} */
const self = this;
/** @type {RouteModel} */
this.route = route;
/** @type {number} */
this.i = i;
/** @type {number} */
this.longitude = longitude;
/** @type {number} */
this.latitude = latitude;
/** @type {any|null} */
this.marker = null;
/** @type {any|null} */
this.line = null;
/** @type {number} */
this.distance = 0;
/** @type {object.<string, any|null>} */
this.attributes = {
/** @type {boolean} */
visible : true,
/** @type {boolean} */
selected : true
};
/** @type {EventModel} */
this.on_change = new EventModel();
/** @type {EventModel} */
this.on_click = new EventModel();
/** @type {EventModel} */
this.on_drop = new EventModel();
/**
* @returns {void}
* @access private
*/
const constructor = () => {
route.routes_maker.map.driver.add_dot(self);
self.on_click.add(() => {
self.remove();
});
self.on_drop.add((_, longitude, latitude) => {
self.longitude = longitude;
self.latitude = latitude;
self.route.routes_maker.map.driver.redraw_dot_lines(self);
self.recalculate_distance();
});
self.recalculate_distance();
};
/**
* @returns {[number, number]}
* @access public
*/
this.get_point = () => [self.latitude, self.longitude];
/**
* @returns {void}
* @access public
*/
this.remove = () => {
const not_unique = self.i && self.i + 1 < route.dots.length;
route.routes_maker.map.driver.remove_dot(self);
route.dots.splice(self.i, 1);
route.dots.slice(self.i).forEach(dot => {
dot.i --;
});
not_unique && route.routes_maker.map.driver.redraw_dot_lines(route.dots[self.i]);
not_unique && route.dots[self.i].recalculate_distance();
};
/**
* @returns {void}
* @access public
*/
this.recalculate_distance = () => {
/** @type {number} */
const origin = self.distance || 0;
if(self.i){
/** @type {DotModel} */
const previous = route.dots[self.i - 1],
/** @type {number} */
pi_radians = Math.PI / 180,
/** @type {number} */
angle = (
Math.sin((self.latitude - previous.latitude) * pi_radians / 2) ** 2 +
Math.cos(self.latitude * pi_radians) * Math.cos(previous.latitude * pi_radians) *
Math.sin((self.longitude - previous.longitude) * 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);
};
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();
};
/** @type {number} */
DotModel.EARTH_RADIUS = 6371000;
return DotModel;
})();