mirror of
https://gitlab.com/gridtracker.org/gridtracker
synced 2026-08-13 17:52:40 -04:00
Better processing indicator Async load local adif files BIGCTY update 0105 Baby step another step Lint 1 Removed debug and dead code DO9KW DO9KW II Lint free safety commit big baby step Remove uneeded timer more speed opt Massive speed improvements Lint Fixed WSPR grid colors and dimming Auto-mute on single or no audio devices. lint Chinese Google Maps and OAMS spot/decode metering Decodes are small and once a minute. Properly save *all* settings on language change Proper method name and code reduction Moved trackQSO to gtCommon in prep for log event 30 minutes inactivity WSJT-X log event not a heavy hit to stat parsing BIGCTY 0125 version bump for testing A bigger hit on uls lookups, but they won't get stuck as un resolved this way Dumped ULS websql database Save lookupssettings and fix changelog lint fix whitespace? roll version, changelog fix Fix really old bug, always set the liveCallsigns with stations info Moved eslint disabled code to bottom of file Removed last traces of .rect, cleaned up vector layer accessors Removed dead code Local ADIF loads now add to startup log list and auto load when added via dialogs
564 lines
17 KiB
JavaScript
564 lines
17 KiB
JavaScript
/* eslint-disable */
|
|
|
|
// HamGridSquare.js
|
|
// Copyright 2014 Paul Brewer KI6CQ
|
|
// License: MIT License http://opensource.org/licenses/MIT
|
|
//
|
|
// Javascript routines to convert from lat-lon to Maidenhead Grid Squares
|
|
// typically used in Ham Radio Satellite operations and VHF Contests
|
|
//
|
|
// Inspired in part by K6WRU Walter Underwood's python answer
|
|
// http://ham.stackexchange.com/a/244
|
|
// to this stack overflow question:
|
|
// How Can One Convert From Lat/Long to Grid Square
|
|
// http://ham.stackexchange.com/questions/221/how-can-one-convert-from-lat-long-to-grid-square
|
|
//
|
|
function latLonToGridSquare(param1,param2, width = 4){
|
|
let lat=-100.0;
|
|
let lon=0.0;
|
|
let adjLat,adjLon,GLat,GLon,nLat,nLon,gLat,gLon,rLat,rLon;
|
|
let U = 'ABCDEFGHIJKLMNOPQRSTUVWX';
|
|
|
|
// support Chris Veness 2002-2012 LatLon library and
|
|
// other objects with lat/lon properties
|
|
// properties could be getter functions, numbers, or strings
|
|
function toNum(x){
|
|
if (typeof(x) == 'number') return x;
|
|
if (typeof(x) == 'string') return parseFloat(x);
|
|
if (typeof(x) == 'function') return parseFloat(x());
|
|
throw "HamGridSquare -- toNum -- can not convert input: "+x;
|
|
}
|
|
if (typeof(param1)=='object'){
|
|
if (param1.length == 2){
|
|
lat = toNum(param1[0]);
|
|
lon = toNum(param1[1]);
|
|
} else if (('lat' in param1) && ('lon' in param1)){
|
|
lat = toNum(param1.lat);
|
|
lon = toNum(param1.lon);
|
|
} else if (('latitude' in param1) && ('longitude' in param1)){
|
|
lat = toNum(param1.latitude);
|
|
lon = toNum(param1.longitude);
|
|
} else {
|
|
throw "HamGridSquare -- can not convert object -- "+param1;
|
|
}
|
|
} else {
|
|
lat = toNum(param1);
|
|
lon = toNum(param2);
|
|
}
|
|
if (isNaN(lat)) throw "lat is NaN";
|
|
if (isNaN(lon)) throw "lon is NaN";
|
|
if (Math.abs(lat) == 90.0) throw "grid g_grids invalid at N/S poles";
|
|
if (Math.abs(lat) > 90) throw "invalid latitude: "+lat;
|
|
if (Math.abs(lon) > 180)
|
|
{
|
|
if ( lon > 180 )
|
|
{
|
|
var temp = lon + 360;
|
|
temp = temp % 360;
|
|
lon = temp - 360;
|
|
}
|
|
while ( lon < -180 )
|
|
{
|
|
lon += 180;
|
|
lon = 180 + lon;
|
|
} // 53032
|
|
}
|
|
adjLat = lat + 90;
|
|
adjLon = lon + 180;
|
|
GLat = U[Math.trunc(adjLat/10)];
|
|
GLon = U[Math.trunc(adjLon/20)];
|
|
nLat = ''+Math.trunc(adjLat % 10);
|
|
nLon = ''+Math.trunc((adjLon/2) % 10);
|
|
|
|
if (width == 4)
|
|
{
|
|
return GLon+GLat+nLon+nLat;
|
|
}
|
|
else
|
|
{
|
|
rLat = (adjLat - Math.trunc(adjLat)) * 60;
|
|
rLon = (adjLon - 2*Math.trunc(adjLon/2)) *60;
|
|
gLat = U[Math.trunc(rLat/2.5)];
|
|
gLon = U[Math.trunc(rLon/5)];
|
|
return GLon+GLat+nLon+nLat+gLon+gLat;
|
|
}
|
|
}
|
|
|
|
var MyCircle = {
|
|
|
|
validateRadius: function(unit) {
|
|
var r = {'M': 6371009, 'KM': 6371.009, 'MI': 3958.761, 'NM': 3440.070, 'YD': 6967420, 'FT': 20902260, 'DG':57.2958};
|
|
if ( unit in r ) return r[unit];
|
|
else return unit;
|
|
},
|
|
|
|
distance: function(lat1, lon1, lat2, lon2, unit) {
|
|
if ( unit == undefined ) unit = 'KM';
|
|
var r = this.validateRadius(unit);
|
|
lat1 *= Math.PI / 180;
|
|
lon1 *= Math.PI / 180;
|
|
lat2 *= Math.PI / 180;
|
|
lon2 *= Math.PI / 180;
|
|
var lonDelta = lon2 - lon1;
|
|
var a = Math.pow(Math.cos(lat2) * Math.sin(lonDelta) , 2) + Math.pow(Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lonDelta) , 2);
|
|
var b = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lonDelta);
|
|
var angle = Math.atan2(Math.sqrt(a) , b);
|
|
|
|
return angle;
|
|
},
|
|
|
|
bearing: function(lat1, lon1, lat2, lon2) {
|
|
lat1 *= Math.PI / 180;
|
|
lon1 *= Math.PI / 180;
|
|
lat2 *= Math.PI / 180;
|
|
lon2 *= Math.PI / 180;
|
|
var lonDelta = lon2 - lon1;
|
|
var y = Math.sin(lonDelta) * Math.cos(lat2);
|
|
var x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lonDelta);
|
|
var brng = Math.atan2(y, x);
|
|
brng = brng * (180 / Math.PI);
|
|
|
|
if ( brng < 0 ) { brng += 360; }
|
|
|
|
return brng;
|
|
},
|
|
|
|
destination: function(lat1, lon1, brng, dt, unit) {
|
|
if ( unit == undefined ) unit = 'KM';
|
|
var r = this.validateRadius(unit);
|
|
lat1 *= Math.PI / 180;
|
|
lon1 *= Math.PI / 180;
|
|
var lat3 = Math.asin(Math.sin(lat1) * Math.cos(dt / r) + Math.cos(lat1) * Math.sin(dt / r) * Math.cos( brng * Math.PI / 180 ));
|
|
var lon3 = lon1 + Math.atan2(Math.sin( brng * Math.PI / 180 ) * Math.sin(dt / r) * Math.cos(lat1) , Math.cos(dt / r) - Math.sin(lat1) * Math.sin(lat3));
|
|
|
|
return {
|
|
'LAT': lat3 * 180 / Math.PI,
|
|
'LON': lon3 * 180 / Math.PI
|
|
};
|
|
}
|
|
|
|
}
|
|
|
|
if (typeof module != 'undefined' && module.exports) {
|
|
module.exports = MyCircle;
|
|
} else {
|
|
window['MyCircle'] = MyCircle;
|
|
}
|
|
|
|
|
|
/**
|
|
* XML2jsobj v1.0
|
|
* Converts XML to a JavaScript object
|
|
* so it can be handled like a JSON message
|
|
*
|
|
* By Craig Buckler, @craigbuckler, http://optimalworks.net
|
|
*
|
|
* As featured on SitePoint.com:
|
|
* http://www.sitepoint.com/xml-to-javascript-object/
|
|
*
|
|
* Please use as you wish at your own risk.
|
|
*/
|
|
|
|
function XML2jsobj(node) {
|
|
|
|
var data = null;
|
|
|
|
// append a value
|
|
function Add(name, value) {
|
|
if (value == null) return;
|
|
if (data == null) data = {};
|
|
if (data[name]) {
|
|
if (data[name].constructor != Array) {
|
|
data[name] = [data[name]];
|
|
}
|
|
data[name][data[name].length] = value;
|
|
}
|
|
else {
|
|
data[name] = value;
|
|
}
|
|
};
|
|
|
|
// element attributes
|
|
var c, cn;
|
|
for (c = 0; cn = node.attributes[c]; c++) {
|
|
Add(cn.name, cn.value);
|
|
}
|
|
|
|
// child elements
|
|
for (c = 0; cn = node.childNodes[c]; c++) {
|
|
if (cn.nodeType == 1) {
|
|
if (cn.childNodes.length == 1 && cn.firstChild.nodeType == 3) {
|
|
// text value
|
|
Add(cn.nodeName, cn.firstChild.nodeValue);
|
|
}
|
|
else {
|
|
// sub-object
|
|
Add(cn.nodeName, XML2jsobj(cn));
|
|
}
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// From https://pskreporter.info/
|
|
// Many many thanks!!!
|
|
function flightFeature(line, opts, layer, canAnimate) {
|
|
var steps = opts.steps;
|
|
// Map coords into lat lngs
|
|
var start = ol.proj.toLonLat(line[0]);
|
|
var end = ol.proj.toLonLat(line[1]);
|
|
var generator = new arc.GreatCircle({ x: start[0], y: start[1] }, { x: end[0], y: end[1] });
|
|
var path = generator.Arc(steps, { offset: 10 });
|
|
|
|
line = [];
|
|
var geom = path.geometries;
|
|
var lonOff = 0;
|
|
var lastc = 0;
|
|
for (var j = 0; j < geom.length; j++) {
|
|
var ls = geom[j];
|
|
for (var i = 0; i < ls.coords.length; i++) {
|
|
var c = ls.coords[i];
|
|
if (isNaN(c[0])) {
|
|
continue;
|
|
}
|
|
if (Math.abs(lastc - c[0]) > 270) {
|
|
// Wrapped
|
|
if (c[0] < lastc) {
|
|
lonOff += 360;
|
|
} else {
|
|
lonOff -= 360;
|
|
}
|
|
}
|
|
lastc = c[0];
|
|
line.push(ol.proj.fromLonLat([ c[0] + lonOff, c[1]]));
|
|
}
|
|
}
|
|
if (line.length == 0) {
|
|
line.push(ol.proj.fromLonLat(start));
|
|
}
|
|
|
|
var dash = [];
|
|
var dashOff = 0;
|
|
if ( canAnimate == true && GT.mapSettings.animate == true )
|
|
{
|
|
dash = GT.flightPathLineDash;
|
|
dashOff = GT.flightPathTotal - GT.flightPathOffset;
|
|
}
|
|
|
|
var featureArrow = new ol.Feature(new ol.geom.Point(line[0]));
|
|
|
|
|
|
line = new ol.geom.LineString(line);
|
|
var feature = new ol.Feature({ geometry: line, prop: 'flight' });
|
|
|
|
feature.setStyle(new ol.style.Style({
|
|
stroke: new ol.style.Stroke({ color: opts.color, width: opts.weight, lineDash: dash, lineDashOffset:dashOff}) }));
|
|
|
|
|
|
var stroke = new ol.style.Stroke({color: opts.color, width: opts.weight});
|
|
var thisStle = new ol.style.Style({
|
|
image: new ol.style.Circle({
|
|
stroke: stroke,
|
|
radius: 3
|
|
})
|
|
})
|
|
featureArrow.setStyle(thisStle);
|
|
feature.Arrow = featureArrow;
|
|
|
|
GT.layerSources[layer].addFeature(featureArrow);
|
|
GT.layerSources[layer].addFeature(feature);
|
|
return feature;
|
|
}
|
|
|
|
|
|
function rad2deg (r) { return (57.29578*r); }
|
|
function deg2rad (d) { return (0.01745329*d); }
|
|
|
|
function sind( x) { return (sin(deg2rad(x))); }
|
|
function cosd( x) { return (cos(deg2rad(x))); }
|
|
function tand( x) { return (tan(deg2rad(x))); }
|
|
function acosd(x) { return (rad2deg(acos(x))); }
|
|
function atand(x) { return (rad2deg(atan(x))); }
|
|
|
|
function sin(x) { return Math.sin(x); }
|
|
function cos(x) { return Math.cos(x); }
|
|
function atan2(x,y) { return Math.atan2(x,y); }
|
|
function sqrt(x) { return Math.sqrt(x); }
|
|
function fmod(a,b) { return Number((a - (Math.floor(a / b) * b)).toPrecision(8)); };
|
|
|
|
/* given seconds since 1/1/1970 compute sublunar lat and long.
|
|
* http://www.stjarnhimlen.se/comp/ppcomp.html
|
|
*/
|
|
function subLunar (t)
|
|
{
|
|
// want days since 1999 Dec 31, 0:00 UT
|
|
d = (t - 946598400)/(3600.0*24.0);
|
|
|
|
/* use this if given year month day hour
|
|
* double d = 367*y - 7 * ( y + (m+9)/12 ) / 4 + 275*m/9 + D - 730530; // all integer divisions
|
|
* d = d + UT/24.0;
|
|
*/
|
|
|
|
M_PI = Math.PI;
|
|
// obliquity of the ecliptic
|
|
ecl = M_PI/180.0*(23.4393 - 3.563E-7 * d);
|
|
|
|
/* N = longitude of the ascending node
|
|
* i = inclination to the ecliptic
|
|
* w = argument of perihelion
|
|
* a = semi-major axis
|
|
* e = eccentricity (0=circle, 0-1=ellipse, 1=parabola)
|
|
* M = mean anomaly (0 at perihelion; increases uniformly with time)
|
|
*/
|
|
|
|
// lunar orbital elements, with respect to Earth
|
|
N_m = M_PI/180.0*(125.1228 - 0.0529538083 * d);
|
|
i_m = M_PI/180.0*(5.1454);
|
|
w_m = M_PI/180.0*(318.0634 + 0.1643573223 * d);
|
|
a_m = 60.2666; // Earth radii
|
|
e_m = 0.054900;
|
|
M_m = M_PI/180.0*(115.3654 + 13.0649929509 * d);
|
|
|
|
// solar orbital elements (really Earth's)
|
|
// double N_s = M_PI/180.0 * (0.0);
|
|
// double i_s = M_PI/180.0 * (0.0);
|
|
w_s = M_PI/180.0 * (282.9404 + 4.70935E-5 * d);
|
|
// double a_s = 1.000000; // AU
|
|
// double e_s = 0.016709 - 1.151E-9 * d;
|
|
M_s = M_PI/180.0 * (356.0470 + 0.9856002585 * d);
|
|
|
|
// solar eccentric anomaly
|
|
// double E_s = M_s + e_s * sin(M_s) * ( 1.0 + e_s * cos(M_s) );
|
|
|
|
// eccentric anomaly, no need to refine if e < ~0.05
|
|
E_m = M_m + e_m * sin(M_m) * ( 1.0 + e_m * cos(M_m) );
|
|
|
|
// solar distance and true anomaly
|
|
// double xv_s = cos(E_s) - e_s;
|
|
// double yv_s = sqrt(1.0 - e_s*e_s) * sin(E_s);
|
|
// double v_s = atan2( yv_s, xv_s );
|
|
// double r_s = sqrt( xv_s*xv_s + yv_s*yv_s );
|
|
|
|
// lunar distance and true anomaly
|
|
xv_m = a_m * ( cos(E_m) - e_m );
|
|
yv_m = a_m * ( sqrt(1.0 - e_m*e_m) * sin(E_m) );
|
|
v_m = atan2 ( yv_m, xv_m );
|
|
r_m = sqrt ( xv_m*xv_m + yv_m*yv_m );
|
|
|
|
// ideal (without perturbations) geocentric ecliptic position in 3-dimensional space:
|
|
xh_m = r_m * ( cos(N_m) * cos(v_m+w_m) - sin(N_m) * sin(v_m+w_m) * cos(i_m) );
|
|
yh_m = r_m * ( sin(N_m) * cos(v_m+w_m) + cos(N_m) * sin(v_m+w_m) * cos(i_m) );
|
|
zh_m = r_m * ( sin(v_m+w_m) * sin(i_m) );
|
|
|
|
// ecliptic long and lat
|
|
lonecl_m = atan2( yh_m, xh_m );
|
|
latecl_m = atan2( zh_m, sqrt(xh_m*xh_m+yh_m*yh_m) );
|
|
|
|
// add enough perturbations to yield max error 0.25 degrees long, 0.15 degs lat
|
|
L_s = M_s + w_s; // Mean Longitude of the Sun (Ns=0)
|
|
L_m = M_m + w_m + N_m; // Mean longitude of the Moon
|
|
D_m = L_m - L_s; // Mean elongation of the Moon
|
|
F_m = L_m - N_m; // Argument of latitude for the Moon
|
|
lonecl_m += M_PI/180.0 * (-1.274 * sin(M_m - 2*D_m)); // Ptolemy's "Evection"
|
|
lonecl_m += M_PI/180.0 * ( 0.658 * sin(2*D_m)); // Brahe's "Variation"
|
|
lonecl_m += M_PI/180.0 * ( 0.186 * sin(M_s)); // Brahe's "Yearly Equation"
|
|
latecl_m += M_PI/180.0 * (-0.173 * sin(F_m - 2*D_m));
|
|
|
|
// convert back to geocentric, now with perturbations applied
|
|
xh_m = r_m * cos(lonecl_m) * cos(latecl_m);
|
|
yh_m = r_m * sin(lonecl_m) * cos(latecl_m);
|
|
zh_m = r_m * sin(latecl_m);
|
|
|
|
// lunar ecliptic to geocentric (already)
|
|
xg_m = xh_m;
|
|
yg_m = yh_m;
|
|
zg_m = zh_m;
|
|
|
|
// convert to equatorial by rotating ecliptic by obliquity
|
|
xe_m = xg_m;
|
|
ye_m = yg_m * cos(ecl) - zg_m * sin(ecl);
|
|
ze_m = yg_m * sin(ecl) + zg_m * cos(ecl);
|
|
|
|
// compute the planet's Right Ascension (RA) and Declination (Dec):
|
|
RA = 180/M_PI * fmod (atan2( ye_m, xe_m ) + 2*M_PI, 2*M_PI); // degrees
|
|
Dec = atan2( ze_m, sqrt(xe_m*xe_m+ye_m*ye_m) ); // rads
|
|
|
|
ll = Object();
|
|
ll.lat = Dec;
|
|
ll.lat_d = rad2deg(ll.lat);
|
|
|
|
JD = (t/86400.0) + 2440587.5;
|
|
D = JD - 2451545.0;
|
|
GMST = fmod(15*(18.697374558 + 24.06570982441908*D), 360.0);
|
|
ll.lng_d = fmod(RA-GMST+36000.0+180.0, 360.0) - 180.0;
|
|
ll.lng = deg2rad(ll.lng_d);
|
|
|
|
data = Object();
|
|
data.ll = [ll.lng_d,ll.lat_d];
|
|
data.RA = RA/15;
|
|
data.Dec = 180/M_PI*Dec;
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
|
|
function doRAconvert(lg, la, ras, decs) {
|
|
|
|
jd=datetojd();
|
|
lgt=lg;
|
|
lat=rad(la);
|
|
ra=ras;
|
|
dec=rad(decs);
|
|
st=sidTime(jd-2400000.5, lgt)
|
|
|
|
return convert(ra, dec, st,lat);
|
|
|
|
}
|
|
|
|
|
|
|
|
function fraction(x) {
|
|
x=x-Math.floor(x)
|
|
if(x<0) {
|
|
x++
|
|
}
|
|
return(x)
|
|
}
|
|
|
|
function sidTime(mjd, lambda) {
|
|
mjdo=Math.floor(mjd)
|
|
ut=(mjd-mjdo)*24
|
|
t=(mjdo-51544.5)/36525.0
|
|
gmst=6.697374558+1.0027379093*ut+(8640184.812866+(0.093104-6.2E-6*t)*t)*t/3600.0
|
|
return(24.0*fraction((gmst+lambda/15.0)/24.0))
|
|
}
|
|
|
|
|
|
function datetojd(datestring)
|
|
{
|
|
jd = (timeNowSec() /86400.0) + 2440587.5;
|
|
return jd
|
|
}
|
|
|
|
|
|
function deg(angle) {
|
|
return angle*180/Math.PI
|
|
}
|
|
|
|
function rad(angle) {
|
|
return angle*Math.PI/180
|
|
}
|
|
|
|
function convert(ra, dec, lmst,lat) {
|
|
hangle=rad((lmst-ra)*15)
|
|
sinalt=Math.sin(dec)*Math.sin(lat)+Math.cos(dec)*Math.cos(hangle)*Math.cos(lat)
|
|
alt=Math.asin(sinalt)
|
|
sinaz=-Math.cos(dec)*Math.sin(hangle)/Math.cos(alt)
|
|
cosaz=Math.sin(dec)*Math.cos(lat)-Math.cos(dec)*Math.cos(hangle)*Math.sin(lat)
|
|
if(cosaz <= 0.0) {
|
|
az=Math.PI-Math.asin(sinaz)
|
|
} else {
|
|
if(sinaz <= 0.0) {
|
|
az=2*Math.PI+Math.asin(sinaz)
|
|
} else {
|
|
az=Math.asin(sinaz)
|
|
}
|
|
}
|
|
|
|
var data = Object();
|
|
data.azimuth = deg(az);
|
|
data.elevation = deg(alt);
|
|
|
|
return data;
|
|
}
|
|
|
|
function isMergeableObject(val) {
|
|
var nonNullObject = val && typeof val == 'object'
|
|
|
|
return nonNullObject
|
|
&& Object.prototype.toString.call(val) !== '[object RegExp]'
|
|
&& Object.prototype.toString.call(val) !== '[object Date]'
|
|
}
|
|
|
|
function emptyTarget(val) {
|
|
return Array.isArray(val) ? [] : {}
|
|
}
|
|
|
|
function cloneIfNecessary(value, optionsArgument) {
|
|
var clone = optionsArgument && optionsArgument.clone == true
|
|
return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value
|
|
}
|
|
|
|
function defaultArrayMerge(target, source, optionsArgument) {
|
|
var destination = target.slice()
|
|
source.forEach(function(e, i) {
|
|
if (typeof destination[i] == 'undefined') {
|
|
destination[i] = cloneIfNecessary(e, optionsArgument)
|
|
} else if (isMergeableObject(e)) {
|
|
destination[i] = deepmerge(target[i], e, optionsArgument)
|
|
} else if (target.indexOf(e) == -1) {
|
|
destination.push(cloneIfNecessary(e, optionsArgument))
|
|
}
|
|
})
|
|
return destination
|
|
}
|
|
|
|
function mergeObject(target, source, optionsArgument) {
|
|
var destination = {}
|
|
if (isMergeableObject(target)) {
|
|
Object.keys(target).forEach(function (key) {
|
|
destination[key] = cloneIfNecessary(target[key], optionsArgument)
|
|
})
|
|
}
|
|
Object.keys(source).forEach(function (key) {
|
|
if (!isMergeableObject(source[key]) || !target[key]) {
|
|
destination[key] = cloneIfNecessary(source[key], optionsArgument)
|
|
} else {
|
|
destination[key] = deepmerge(target[key], source[key], optionsArgument)
|
|
}
|
|
})
|
|
return destination
|
|
}
|
|
|
|
function deepmerge(target, source, optionsArgument) {
|
|
var array = Array.isArray(source);
|
|
var options = optionsArgument || { arrayMerge: defaultArrayMerge }
|
|
var arrayMerge = options.arrayMerge || defaultArrayMerge
|
|
|
|
if (array) {
|
|
return Array.isArray(target) ? arrayMerge(target, source, optionsArgument) : cloneIfNecessary(source, optionsArgument)
|
|
} else {
|
|
return mergeObject(target, source, optionsArgument)
|
|
}
|
|
}
|
|
|
|
deepmerge.all = function deepmergeAll(array, optionsArgument) {
|
|
if (!Array.isArray(array) || array.length < 2) {
|
|
throw new Error('first argument should be an array with at least two elements')
|
|
}
|
|
|
|
// we are sure there are at least 2 values, so it is safe to have no initial value
|
|
return array.reduce(function(prev, next) {
|
|
return deepmerge(prev, next, optionsArgument)
|
|
})
|
|
}
|
|
|
|
|
|
// https://stackoverflow.com/questions/3942878/how-to-decide-font-color-in-white-or-black-depending-on-background-color
|
|
function pickTextColorBasedOnBgColorAdvanced(bgColor, lightColor, darkColor) {
|
|
var color = (bgColor.charAt(0) == '#') ? bgColor.substring(1, 7) : bgColor;
|
|
var r = parseInt(color.substring(0, 2), 16); // hexToR
|
|
var g = parseInt(color.substring(2, 4), 16); // hexToG
|
|
var b = parseInt(color.substring(4, 6), 16); // hexToB
|
|
var uicolors = [r / 255, g / 255, b / 255];
|
|
var c = uicolors.map((col) => {
|
|
if (col <= 0.03928) {
|
|
return col / 12.92;
|
|
}
|
|
return Math.pow((col + 0.055) / 1.055, 2.4);
|
|
});
|
|
var L = (0.2126 * c[0]) + (0.7152 * c[1]) + (0.0722 * c[2]);
|
|
return (L > 0.179) ? darkColor : lightColor;
|
|
}
|