UNPKG

maplibre-gl-nightlayer

Version:

A Night Layer for MapLibre GL JS

73 lines (58 loc) 6.98 kB
import{MercatorCoordinate as f,createTileMesh as d}from"maplibre-gl";function p(n){return n*Math.PI/180}function g(n){return n/Math.PI*180}function l(n){const[t,r,u,o]=n.map(a=>a/255);return[t*o,r*o,u*o,o]}function b(n){n=n||new Date;const t=(n.getTime()-Date.UTC(n.getUTCFullYear(),0,0))/864e5,r=2*Math.PI/365.24,u=p(23.44),o=.0167,a=(t+9)*r,e=a+2*o*Math.sin((t-3)*r),i=(a-Math.atan2(Math.sin(e),Math.cos(e)*Math.cos(u)))/Math.PI,s=720*(i-Math.trunc(i+.5)),h=-15*(n.getUTCHours()+n.getUTCMinutes()/60+n.getUTCSeconds()/3600+n.getUTCMilliseconds()/36e5-12+s/60),m=g(Math.asin(Math.sin(-u)*Math.cos(e)));return{lng:h,lat:m}}class _{id="nightlayer";type="custom";renderingMode="2d";#n;#a;#c;#f;#s;#o;#u;#h;#e;#t;#i;#r;#l;#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(){const 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 b(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.#f}setDaytimeColor(t){this.#f=[...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,r){this.#e=new Map,this.#i=r.createBuffer(),this.#r=r.createBuffer(),this.#t=t}onRemove(){this.#e=void 0,this.#t=void 0,this.#i=void 0,this.#r=void 0}#p(t,r){const o=`#version 300 es precision highp float; in vec2 a_position; out vec2 v_position; ${!r.vertexShaderPrelude?` uniform mat4 u_matrix; vec4 projectTile(vec2 pos) { return u_matrix * vec4(pos, 0., 1.); } `:` ${r.vertexShaderPrelude} ${r.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,o),t.compileShader(e);const i=t.createShader(t.FRAGMENT_SHADER);if(!i)throw new Error("failed to create fragment shader");t.shaderSource(i,a),t.compileShader(i);const s=t.createProgram();if(!s)throw new Error("failed to create program");return t.attachShader(s,e),t.attachShader(s,i),t.linkProgram(s),s}#g(t){if(!this.#t||!this.#i||!this.#r)return;const[r,u]=this.#t.getBounds().toArray(),o=Math.floor(f.fromLngLat(r).x),a=Math.ceil(f.fromLngLat(u).x),e=this.#t.style?.projection?.name==="globe"?"globe":[o,a].join(":");if(e===this.#m)return;let i;e==="globe"?(i=d({granularity:100,generateBorders:!1,extendToNorthPole:!0,extendToSouthPole:!0},"16bit"),i.vertices=new Float32Array(new Int16Array(i.vertices)).map(s=>s/8192).buffer):i={vertices:new Float32Array([o,0,a,0,o,1,o,1,a,0,a,1]).buffer,indices:new Uint16Array([0,1,2,3,4,5]).buffer,uses32bitIndices:!1},t.bindBuffer(t.ARRAY_BUFFER,this.#i),t.bufferData(t.ARRAY_BUFFER,i.vertices,t.DYNAMIC_DRAW),t.bindBuffer(t.ARRAY_BUFFER,null),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.#r),t.bufferData(t.ELEMENT_ARRAY_BUFFER,i.indices,t.DYNAMIC_DRAW),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,null),this.#l=i.indices.byteLength/2,this.#m=e}render(t,r,u){if(u||(u=r),!this.#e||!this.#i||!this.#r||!this.#t)return;const o=u.shaderData||{},a=o.variantName||"default";this.#e.has(a)||this.#e.set(a,this.#p(t,o));const e=this.#e.get(a);if(!e)return;const{lng:i,lat:s}=this.getSubsolarPoint();if(t.useProgram(e),t.uniform2fv(t.getUniformLocation(e,"u_subsolar"),[i,s]),t.uniform1f(t.getUniformLocation(e,"u_opacity"),this.#a),t.uniform4fv(t.getUniformLocation(e,"u_night_color"),l(this.#c)),t.uniform4fv(t.getUniformLocation(e,"u_daytime_color"),l(this.#f)),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){const 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,r);this.#g(t),t.bindBuffer(t.ARRAY_BUFFER,this.#i),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.#r);const c=t.getAttribLocation(e,"a_position");t.enableVertexAttribArray(c),t.vertexAttribPointer(c,2,t.FLOAT,!1,0,0),t.drawElements(t.TRIANGLES,this.#l,t.UNSIGNED_SHORT,0)}}var C=_;export{_ as NightLayer,C as default,b as getSubsolarPoint};