openct-tasks/_common/modules/pemFioi/components/geography/geography.js

217 lines
6.3 KiB
JavaScript

// Geography library
var Geography = {};
// distance calculator
Geography.DistanceCalculator = function(unit) {
function getEarthRadius() {
var earthRadius = {
'yards': 6967410,
'km': 6371,
'miles': 3959,
'metres': 6371000,
'feet': 20902231
};
return earthRadius[unit] || earthRadius['km'];
}
var r = getEarthRadius(unit)
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
this.getDistance = function(point1, point2) {
var dlat = deg2rad(point2.lat - point1.lat);
var dlon = deg2rad(point2.lng - point1.lng);
var a =
Math.sin(dlat / 2) * Math.sin(dlat / 2) +
Math.cos(deg2rad(point1.lat)) * Math.cos(deg2rad(point2.lat)) *
Math.sin(dlon / 2) * Math.sin(dlon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return r * c;
}
this.getMidPoint = function(point1, point2) {
var lat1 = deg2rad(point1.lat);
var lng1 = deg2rad(point1.lng);
var lat2 = deg2rad(point2.lat);
var lng2 = deg2rad(point2.lng);
var dlng = lng2 - lng1;
var bx = Math.cos(lat2) * Math.cos(dlng);
var by = Math.cos(lat2) * Math.sin(dlng);
var lat = Math.atan2(
Math.sin(lat1) + Math.sin(lat2),
Math.sqrt((Math.cos(lat1) + bx) * (Math.cos(lat1) + bx) + by * by)
);
var lng = lng1 + Math.atan2(by, Math.cos(lat1) + bx);
return {
lat: lat * 180 / Math.PI,
lng: lng * 180 / Math.PI
}
}
}
// map renderer 2D
Geography.Renderer2D = function(options) {
function ImageLoader(src, onLoad) {
var loaded = false;
var img = new Image();
img.src = src;
img.onload = function() {
loaded = true;
onLoad && onLoad();
}
img.onerror = function() {
console.error('Error loading image: ' + src);
}
this.get = function() {
return loaded ? img : null;
}
}
// measure text size
var span = document.createElement('span');
span.style.whiteSpace = 'nowrap';
span.style.display = 'inline';
span.style.visibility = 'hidden';
span.style.font = options.font;
if(options.display) {
document.body.append(span);
}
function getTextSize(text) {
span.innerHTML = text;
return {
width: span.offsetWidth,
height: span.offsetHeight
}
}
function CoordinatesConverter() {
var map_lat_bottomRad = options.map_lat_bottom * Math.PI / 180;
var mapLngDelta = (options.map_lng_right - options.map_lng_left)
var worldMapWidth = ((options.width / mapLngDelta) * 360) / (2 * Math.PI)
var mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(map_lat_bottomRad)) / (1 - Math.sin(map_lat_bottomRad))))
this.x = function(lng) {
return (lng - options.map_lng_left) * (options.width / mapLngDelta);
}
this.y = function(lat) {
var latitudeRad = lat * Math.PI / 180;
return options.height - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitudeRad)) / (1 - Math.sin(latitudeRad)))) - mapOffsetY)
}
}
function rgba(colors, opacity) {
return 'rgba(' + colors.r + ',' + colors.g + ',' + colors.b + ',' + opacity + ')';
}
this.clear = function() {
var img = images.map.get();
if(img) {
context.drawImage(img, 0, 0, options.width, options.height)
} else {
context.fillStyle = rgba(options.background_color, 1);
context.fillRect(0, 0, options.width, options.height)
}
}
this.line = function(lng1, lat1, lng2, lat2, opacity) {
context.lineWidth = options.line_width;
context.strokeStyle = rgba(options.line_color, opacity);
context.beginPath();
context.moveTo(coordinates.x(lng1), coordinates.y(lat1));
context.lineTo(coordinates.x(lng2), coordinates.y(lat2));
context.stroke();
}
this.pin = function(lng, lat, label) {
var x = coordinates.x(lng);
var y = coordinates.y(lat);
var img = images.pin.get();
if(img) {
var w = options.pin_scale * img.width;
var h = options.pin_scale * img.height;
context.drawImage(img, x - w * 0.5, y - h, w, h);
}
context.textAlign = 'center';
context.font = options.font;
if(options.truncate_labels) {
label = label.substr(0, 2);
context.fillStyle = rgba(options.text_color, 1);
context.fillText(label, x, y - h * 0.6)
} else {
var ts = getTextSize(label);
context.fillStyle = rgba(options.background_color, 1);
var tl = x - 0.5 * ts.width;
if(tl < 0) {
x -= tl;
tl = 0;
} else if(tl + ts.width > options.width) {
x = options.width - ts.width * 0.5;
tl = options.width - ts.width;
}
context.fillRect(
tl,
y + 4,
ts.width,
ts.height
);
context.fillStyle = rgba(options.text_color, 1);
context.textBaseline = 'middle';
context.fillText(label, x, y + 4 + ts.height * 0.5);
}
}
this.addMistake = function(lng, lat) {
var x = coordinates.x(lng);
var y = coordinates.y(lat);
context.strokeStyle = '#FF0000';
context.lineWidth = options.line_width;
context.beginPath();
context.arc(x, y, 20, 20, 0, 2 * Math.PI);
context.stroke();
}
// init
var images = {
map: new ImageLoader(options.map_file, this.clear.bind(this)),
pin: new ImageLoader(options.pin_file)
}
var canvas = document.createElement('canvas');
canvas.width = options.width;
canvas.height = options.height;
if(options.display) {
options.parent.appendChild(canvas);
}
var context = canvas.getContext('2d');
var coordinates = new CoordinatesConverter();
this.destroy = function() {
options.parent.removeChild(canvas);
canvas = null;
}
}