maplibre-gl-nightlayer
Version:
A Night Layer for MapLibre GL JS
73 lines (58 loc) • 7.42 kB
JavaScript
"use strict";var nightLayer=(()=>{var f=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var R=(r,t)=>{for(var o in t)f(r,o,{get:t[o],enumerable:!0})},M=(r,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of v(t))!C.call(r,i)&&i!==o&&f(r,i,{get:()=>t[i],enumerable:!(s=_(t,i))||s.enumerable});return r};var L=r=>M(f({},"__esModule",{value:!0}),r);var w={};R(w,{NightLayer:()=>c,default:()=>y,getSubsolarPoint:()=>g});var{createTileMesh:d,MercatorCoordinate:m}=maplibregl;function x(r){return r*Math.PI/180}function A(r){return r/Math.PI*180}function p(r){let[t,o,s,i]=r.map(a=>a/255);return[t*i,o*i,s*i,i]}function g(r){r=r||new Date;let t=(r.getTime()-Date.UTC(r.getUTCFullYear(),0,0))/864e5,o=2*Math.PI/365.24,s=x(23.44),i=.0167,a=(t+9)*o,e=a+2*i*Math.sin((t-3)*o),n=(a-Math.atan2(Math.sin(e),Math.cos(e)*Math.cos(s)))/Math.PI,u=720*(n-Math.trunc(n+.5)),h=-15*(r.getUTCHours()+r.getUTCMinutes()/60+r.getUTCSeconds()/3600+r.getUTCMilliseconds()/36e5-12+u/60),b=A(Math.asin(Math.sin(-s)*Math.cos(e)));return{lng:h,lat:b}}var c=class{id="nightlayer";type="custom";renderingMode="2d";#n;#a;#c;#l;#s;#o;#u;#h;#e;#t;#r;#i;#f;#m;constructor(t={}){this.#a=t.opacity??.5,this.#u=t.twilightSteps??0,this.#h=t.twilightAttenuation??.5,this.#o=t.updateInterval??1e4,this.setColor(t.color??[0,0,0,255]),this.setDaytimeColor(t.daytimeColor??[0,0,0,0]),this.setDate(t.date??null)}#d(){let t=this.#n===null;this.#s&&(clearInterval(this.#s),this.#s=void 0),t&&this.#o>0&&(this.#s=setInterval(()=>this.#t?.triggerRepaint(),this.#o))}getSubsolarPoint(){return g(this.#n||new Date)}getDate(){return this.#n}setDate(t){this.#n=t,this.#d(),this.#t?.triggerRepaint()}getOpacity(){return this.#a}setOpacity(t){this.#a=t,this.#t?.triggerRepaint()}getColor(){return this.#c}setColor(t){this.#c=[...t.slice(0,3),t?.[3]??255],this.#t?.triggerRepaint()}getDaytimeColor(){return this.#l}setDaytimeColor(t){this.#l=[...t.slice(0,3),t?.[3]??255],this.#t?.triggerRepaint()}getTwilightSteps(){return this.#u}setTwilightSteps(t){this.#u=t,this.#t?.triggerRepaint()}getTwilightAttenuation(){return this.#h}setTwilightAttenuation(t){this.#h=t,this.#t?.triggerRepaint()}getUpdateInterval(){return this.#o}setUpdateInterval(t){this.#o=t,this.#d()}onAdd(t,o){this.#e=new Map,this.#r=o.createBuffer(),this.#i=o.createBuffer(),this.#t=t}onRemove(){this.#e=void 0,this.#t=void 0,this.#r=void 0,this.#i=void 0}#p(t,o){let i=`#version 300 es
precision highp float;
in vec2 a_position;
out vec2 v_position;
${!o.vertexShaderPrelude?`
uniform mat4 u_matrix;
vec4 projectTile(vec2 pos) {
return u_matrix * vec4(pos, 0., 1.);
}
`:`
${o.vertexShaderPrelude}
${o.define}
`}
void main() {
gl_Position = projectTile(a_position);
v_position = a_position;
}
`,a=`#version 300 es
precision highp float;
in vec2 v_position;
out vec4 fragColor;
uniform vec2 u_subsolar;
uniform float u_opacity;
uniform float u_twilight_steps;
uniform float u_twilight_attenuation;
uniform vec4 u_daytime_color;
uniform vec4 u_night_color;
vec2 mercatorToLngLat(vec2 mercator) {
// 0 <= x <= 1, 0 <= y <= 1
float x = mercator.x;
float y = mercator.y;
float lng = x * 360.0 - 180.0;
float lat = degrees(2.0 * atan(exp(${Math.PI} * (1.0 - 2.0 * y))) - ${Math.PI/2});
return vec2(lng, lat);
}
void main() {
vec2 lnglat = mercatorToLngLat(v_position);
vec2 observer = radians(lnglat);
vec2 subsolar = radians(u_subsolar);
float A = sin(observer.y) * sin(subsolar.y);
float B = cos(observer.y) * cos(subsolar.y) * cos(subsolar.x - observer.x);
float altitude = degrees(asin(A + B));
float twilightStepAngle = 6.0;
float twilightBegins = -0.8333333;
float twilightSteps = u_twilight_steps;
// Attenuation for each twilightStepAngle
float att = u_twilight_attenuation;
float twilightLevel = -altitude / twilightStepAngle;
if (twilightSteps > 0.) {
twilightLevel = ceil(clamp(twilightLevel, 0., twilightSteps));
if (altitude > twilightBegins) {
// XXX: Adjust for sunset/sunrise line
twilightLevel = 0.;
}
}
float brightness = clamp(pow(clamp(1. - att, 0., 1.), twilightLevel), 0., 1.);
fragColor = mix(u_night_color, u_daytime_color, brightness) * u_opacity;
}`,e=t.createShader(t.VERTEX_SHADER);if(!e)throw new Error("failed to create vertex shader");t.shaderSource(e,i),t.compileShader(e);let n=t.createShader(t.FRAGMENT_SHADER);if(!n)throw new Error("failed to create fragment shader");t.shaderSource(n,a),t.compileShader(n);let u=t.createProgram();if(!u)throw new Error("failed to create program");return t.attachShader(u,e),t.attachShader(u,n),t.linkProgram(u),u}#g(t){if(!this.#t||!this.#r||!this.#i)return;let[o,s]=this.#t.getBounds().toArray(),i=Math.floor(m.fromLngLat(o).x),a=Math.ceil(m.fromLngLat(s).x),e=this.#t.style?.projection?.name==="globe"?"globe":[i,a].join(":");if(e===this.#m)return;let n;e==="globe"?(n=d({granularity:100,generateBorders:!1,extendToNorthPole:!0,extendToSouthPole:!0},"16bit"),n.vertices=new Float32Array(new Int16Array(n.vertices)).map(u=>u/8192).buffer):n={vertices:new Float32Array([i,0,a,0,i,1,i,1,a,0,a,1]).buffer,indices:new Uint16Array([0,1,2,3,4,5]).buffer,uses32bitIndices:!1},t.bindBuffer(t.ARRAY_BUFFER,this.#r),t.bufferData(t.ARRAY_BUFFER,n.vertices,t.DYNAMIC_DRAW),t.bindBuffer(t.ARRAY_BUFFER,null),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.#i),t.bufferData(t.ELEMENT_ARRAY_BUFFER,n.indices,t.DYNAMIC_DRAW),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,null),this.#f=n.indices.byteLength/2,this.#m=e}render(t,o,s){if(s||(s=o),!this.#e||!this.#r||!this.#i||!this.#t)return;let i=s.shaderData||{},a=i.variantName||"default";this.#e.has(a)||this.#e.set(a,this.#p(t,i));let e=this.#e.get(a);if(!e)return;let{lng:n,lat:u}=this.getSubsolarPoint();if(t.useProgram(e),t.uniform2fv(t.getUniformLocation(e,"u_subsolar"),[n,u]),t.uniform1f(t.getUniformLocation(e,"u_opacity"),this.#a),t.uniform4fv(t.getUniformLocation(e,"u_night_color"),p(this.#c)),t.uniform4fv(t.getUniformLocation(e,"u_daytime_color"),p(this.#l)),t.uniform1f(t.getUniformLocation(e,"u_twilight_steps"),this.#u),t.uniform1f(t.getUniformLocation(e,"u_twilight_attenuation"),this.#h),"getProjectionDataForCustomLayer"in this.#t.transform){let h=this.#t.transform.getProjectionDataForCustomLayer(!0);t.uniformMatrix4fv(t.getUniformLocation(e,"u_projection_fallback_matrix"),!1,h.fallbackMatrix),t.uniformMatrix4fv(t.getUniformLocation(e,"u_projection_matrix"),!1,h.mainMatrix),t.uniform4f(t.getUniformLocation(e,"u_projection_tile_mercator_coords"),...h.tileMercatorCoords),t.uniform4f(t.getUniformLocation(e,"u_projection_clipping_plane"),...h.clippingPlane),t.uniform1f(t.getUniformLocation(e,"u_projection_transition"),h.projectionTransition)}else t.uniformMatrix4fv(t.getUniformLocation(e,"u_matrix"),!1,o);this.#g(t),t.bindBuffer(t.ARRAY_BUFFER,this.#r),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.#i);let l=t.getAttribLocation(e,"a_position");t.enableVertexAttribArray(l),t.vertexAttribPointer(l,2,t.FLOAT,!1,0,0),t.drawElements(t.TRIANGLES,this.#f,t.UNSIGNED_SHORT,0)}},y=c;return L(w);})();