"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.} 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.} 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.} */ 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; })();