Skip to content

Instantly share code, notes, and snippets.

@KoGor KoGor/L.Terminator.js
Last active Aug 29, 2015

Embed
What would you like to do?
Solar Terminator with layers clipping

Solar Terminator with layers clipping. Path generated by Leaflet.Terminator plugin used for clipping layers, night effect on tiles created with help of SVG filter. Your location marked with red star. All works great on firefox. Leaflet + Leaflet.Terminator.

<!DOCTYPE html>
<html>
<head>
<meta charset=UTF-8 />
<title>Solar Terminator with layers clipping</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="L.Terminator.js"></script>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width: 960px; height: 500px; }
</style>
</head>
<body>
<div id='map'></div>
<script>
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
stamenUrl = 'http://{s}.tile.stamen.com/toner/{z}/{x}/{y}.png',
attrib = '&copy; Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> | <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
main = L.tileLayer(osmUrl, {maxZoom: 18, attribution: attrib}),
map = new L.Map('map', {
layers: [main],
center: new L.LatLng(0, 0),
zoom: 1,
minZoom: 1
}),
terminator = L.terminator({
color: '#666666',
resolution: 5
}),
overlay = L.tileLayer(stamenUrl).addTo(map);
overlay.getContainer().style.filter = "url(#luminance_mask)";
overlay.getContainer().style.WebkitFilter = "url(#luminance_mask)";
terminator.addTo(map);
var myIcon = L.icon({
iconUrl: 'star.svg',
iconSize: [20, 20],
iconAnchor: [10, 10],
popupAnchor: [-3, -76]
});
map.locate();
map.on("locationfound", function(e) {
L.marker(e.latlng, {icon: myIcon}).addTo(map);
});
setInterval(function() {updateTerminator(terminator)}, 500);
function updateTerminator(t) {
var t2 = L.terminator({resolution: 5});
t.setLatLngs(t2.getLatLngs());
t.redraw();
clip();
};
var svg = d3.select(".leaflet-overlay-pane").select("svg"),
defs = svg.append("defs"),
clipMask = defs.append("clipPath").attr("id", "clipMask");
clipPath = clipMask.append("path")
.attr("id", "clipPath")
.attr("d", d3.select(terminator._path).attr("d"))
.attr('fill', 'white')
.attr('opacity', 1);
function clip() {
setTimeout(function() {
//Get path from Solar terminator plugin
var pathData = d3.select(terminator._path).attr("d");
clipPath.attr("d", pathData);
overlay.getContainer().style.clipPath = 'url(#clipMask)';
overlay.getContainer().style['-webkit-clip-path'] = 'url(#clipMask)';
}, 100);
};
clip();
map.on('moveend', clip);
map.on('zoomend', clip);
</script>
<svg>
<defs>
<filter id="grayscale">
<feColorMatrix type="saturate" values="0"/>
</filter>
<filter id="luminance_mask">
<feColorMatrix type="luminanceToAlpha"/>
</filter>
</defs>
</svg>
</body>
</html>
/* Terminator.js -- Overlay day/night region on a Leaflet map */
Date.prototype.getJulian = function() {
/* Calculate the present UTC Julian Date. Function is valid after
* the beginning of the UNIX epoch 1970-01-01 and ignores leap
* seconds. */
return (this / 86400000) + 2440587.5;
}
Date.prototype.getGMST = function() {
/* Calculate Greenwich Mean Sidereal Time according to
http://aa.usno.navy.mil/faq/docs/GAST.php */
var julianDay = this.getJulian();
var d = julianDay - 2451545.0;
// Low precision equation is good enough for our purposes.
return (18.697374558 + 24.06570982441908 * d) % 24;
}
L.Terminator = L.Polygon.extend({
options: {
color: '#00',
opacity: 0.5,
fillColor: '#00',
fillOpacity: 0.5,
resolution: 2
},
initialize: function(options) {
this.version = '0.1.0';
this._R2D = 180 / Math.PI;
this._D2R = Math.PI / 180;
L.Util.setOptions(this, options);
var latLng = this._compute(this.options.time || null)
this.setLatLngs(latLng);
},
_sunEclipticPosition: function(julianDay) {
/* Compute the position of the Sun in ecliptic coordinates at
julianDay. Following
http://en.wikipedia.org/wiki/Position_of_the_Sun */
// Days since start of J2000.0
var n = julianDay - 2451545.0;
// mean longitude of the Sun
var L = 280.460 + 0.9856474 * n;
L %= 360;
// mean anomaly of the Sun
var g = 357.528 + 0.9856003 * n;
g %= 360;
// ecliptic longitude of Sun
var lambda = L + 1.915 * Math.sin(g * this._D2R) +
0.02 * Math.sin(2 * g * this._D2R);
// distance from Sun in AU
var R = 1.00014 - 0.01671 * Math.cos(g * this._D2R) -
0.0014 * Math.cos(2 * g * this._D2R);
return {"lambda": lambda, "R": R};
},
_eclipticObliquity: function(julianDay) {
// Following the short term expression in
// http://en.wikipedia.org/wiki/Axial_tilt#Obliquity_of_the_ecliptic_.28Earth.27s_axial_tilt.29
var n = julianDay - 2451545.0;
// Julian centuries since J2000.0
var T = n / 36525;
var epsilon = 23.43929111 -
T * (46.836769 / 3600
- T * (0.0001831 / 3600
+ T * (0.00200340 / 3600
- T * (0.576e-6 / 3600
- T * 4.34e-8 / 3600))));
return epsilon;
},
_sunEquatorialPosition: function(sunEclLng, eclObliq) {
/* Compute the Sun's equatorial position from its ecliptic
* position. Inputs are expected in degrees. Outputs are in
* degrees as well. */
var alpha = Math.atan(Math.cos(eclObliq * this._D2R)
* Math.tan(sunEclLng * this._D2R)) * this._R2D;
var delta = Math.asin(Math.sin(eclObliq * this._D2R)
* Math.sin(sunEclLng * this._D2R)) * this._R2D;
var lQuadrant = Math.floor(sunEclLng / 90) * 90;
var raQuadrant = Math.floor(alpha / 90) * 90;
alpha = alpha + (lQuadrant - raQuadrant);
return {"alpha": alpha, "delta": delta};
},
_hourAngle: function(lng, sunPos, gst) {
/* Compute the hour angle of the sun for a longitude on
* Earth. Return the hour angle in degrees. */
var lst = gst + lng / 15;
return lst * 15 - sunPos.alpha;
},
_latitude: function(ha, sunPos) {
/* For a given hour angle and sun position, compute the
* latitude of the terminator in degrees. */
var lat = Math.atan(-Math.cos(ha * this._D2R) /
Math.tan(sunPos.delta * this._D2R)) * this._R2D;
return lat;
},
_compute: function(time) {
if (time == null)
var today = new Date();
else
var today = new Date(time);
var julianDay = today.getJulian();
var gst = today.getGMST();
var latLng = [];
var ha, lat;
var sunEclPos = this._sunEclipticPosition(julianDay);
var eclObliq = this._eclipticObliquity(julianDay);
var sunEqPos = this._sunEquatorialPosition(sunEclPos.lambda, eclObliq);
for (var i = 0; i <= 720 * this.options.resolution; i++) {
lng = -360 + i / this.options.resolution;
ha = this._hourAngle(lng, sunEqPos, gst);
lat = this._latitude(ha, sunEqPos);
latLng[i+1] = [lat, lng];
}
if (sunEqPos.delta < 0) {
latLng[0] = [90, -360];
latLng[latLng.length] = [90, 360];
} else {
latLng[0] = [-90, -360];
latLng[latLng.length] = [-90, 360];
}
return latLng;
}
});
L.terminator = function(options) {
return new L.Terminator(options);
};
The MIT License (MIT)
Copyright (c) 2014 [KoGor](https://github.com/KoGor)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.