UNPKG

mapboxgl-legend

Version:

Mapbox-GL plugin that automatically draws a legend from layer styles

2 lines (1 loc) 7.69 kB
(function(m,u){typeof exports=="object"&&typeof module<"u"?module.exports=u():typeof define=="function"&&define.amd?define(u):(m=typeof globalThis<"u"?globalThis:m||self,m.LegendControl=u())})(this,function(){"use strict";const m=e=>Array.isArray(e)?e:[e],u=(e,t,n,s=0,o=100)=>(e-t)*(o-s)/(n-t)+s,D=(e,t)=>Array.from({length:Math.ceil(e.length/t)},(n,s)=>e.slice(s*t,s*t+t)),T=(...e)=>e[0].map((t,n)=>e.slice(1).reduce((s,o)=>[...s,o[n]],[t])),S=e=>e.length===2?e:[null,...e],w=e=>e.reduce((t,[n,s],o)=>(o===e.length-1?t.push([[n,null],s]):t.push([[n,e[o+1][0]],s]),t),[]),d=(e,t={})=>{const{classes:n,styles:s,attributes:o,events:r,content:i,appendTo:l}=t,c=document.createElement(e);return n&&m(n).forEach(a=>c.classList.add(a)),s&&Object.entries(s).forEach(a=>c.style.setProperty(...a)),o&&Object.entries(o).forEach(([a,h])=>{h||h===0?c.setAttribute(a,`${h}`):c.removeAttribute(a)}),r&&Object.entries(r).forEach(([a,h])=>c.addEventListener(a,h)),i&&c.append(...m(i).filter(Boolean)),l&&l.appendChild(c),c},F=(e,t,n)=>{const s=Math.max(t,n),o=d("canvas",{attributes:{width:s,height:s}}),r=o.getContext("2d"),i=new ImageData(Uint8ClampedArray.from(e),t,n);return r==null||r.putImageData(i,(s-t)/2,(s-n)/2),o},v=(e,t)=>{const{labels:n={},unit:s=""}=t||{};return Array.isArray(e)?n[`${e}`]??(e[0]===null?`< ${n[`${e[1]}`]||`${e[1]}${s}`}`:e[1]===null?`> ${n[`${e[0]}`]||`${e[0]}${s}`}`:e.map(o=>n[`${o}`]||`${o}${s}`).join(" - ")):e!==null?n[`${e}`]??`${e}${s}`:n.other??"other"},A={},$=(e,t,n)=>{const{getter:s}=e;t.id in A||(A[t.id]=t.filter??null);const o=(i,l)=>{const{delta:c=0}=l||{};if(s)if(i==null)n.setFilter(t.id,A[t.id]);else if(Array.isArray(i)){const[a,h]=i,p=a?[">=",s,a]:!0,g=h?["<",s,h]:!0;n.setFilter(t.id,["all",p,g])}else{const a=typeof i=="number"?["all",[">=",s,i-c],["<=",s,i+c]]:["==",s,i];n.setFilter(t.id,a)}};return{highlight:o,events:i=>({mouseenter:()=>o(i),mouseleave:()=>o(void 0)})}},k={x:0},q=(e,t,n,s)=>{const{inputs:o,stops:r,min:i,max:l}=e,{highlight:c}=$(e,t,n),a=(l-i)/100,h={mouseleave:()=>c(void 0),mousemove:g=>{const{offsetX:f,target:y}=g;k.x=f;const b=y,E=u(f,0,b.offsetWidth,i,l);c(E,{delta:a}),b.style.setProperty("--x",`${f}px`)}},p=r.map(([g,f])=>`${f} ${u(g,i,l)}%`);return d("div",{classes:["gradient",`gradient--${s.highlight?"highlight":""}`],content:[d("p",{classes:"labels",content:o.map(g=>{const f=v(g,t.metadata);return f&&d("span",{styles:{left:`${u(g,i,l)}%`},content:f})})}),d("div",{classes:"bar",styles:{"background-image":`linear-gradient(90deg, ${p})`,"--x":`${k.x||0}px`},events:s.highlight?h:{}})]})},I=(e,t,n,s)=>{const{stops:o}=e,{events:r}=$(e,t,n);return d("ul",{classes:["list","list--color",`list--${s.highlight?"highlight":""}`],content:o.map(([i,l])=>{const c=v(i,t.metadata);return c&&d("li",{styles:{"--color":l},events:s.highlight?r(i):{},content:c})})})},R=(e,t,n,s)=>{switch(e.name){case"interpolate":return q(e,t,n,s);case"match":case"step":case"literal":return I(e,t,n,s);default:return}},U=(e,t,n,s)=>{const{stops:o}=e,{events:r}=$(e,t,n);return d("ul",{classes:["bubbles",`bubbles--${s.highlight?"highlight":""}`],content:o.sort((i,l)=>l[1]-i[1]).map(([i,l])=>{const c=v(i,t.metadata);return c&&d("li",{styles:{"--radius":`${l}px`},events:s.highlight?r(i):{},content:d("span",{content:c})})})})},B=(e,t,n,s)=>{const{stops:o}=e,{events:r}=$(e,t,n);return d("ul",{classes:["list","list--icons",`list--${s.highlight?"highlight":""}`],content:o.map(([i,l])=>{var f;const c=v(i,t.metadata);if(!c)return;const{height:a,width:h,data:p}=((f=n.style.getImage(l))==null?void 0:f.data)||{};if(!a||!h||!p)return;const g=F(p,h,a);return d("li",{events:s.highlight?r(i):{},content:[d("img",{classes:["icon"],attributes:{src:g.toDataURL()}}),c]})})})},N={color:R,radius:U,image:B,pattern:B},x=(e,t)=>D(e.slice(t),2),L={interpolate:e=>x(e,2),match:e=>x(e,1).map(S),step:e=>w([[null,e[1]],...x(e,2)]),literal:e=>[[...e,...e]]},j=e=>Array.isArray(e)&&!!e.length&&typeof e[0]=="string",M=e=>{var a;const[t,...n]=j(e)?e:["literal",e];if(t==="case")return n.slice(1).flatMap(M);const s=(a=L[t])==null?void 0:a.call(L,n);if(!s)return[];const o=t==="literal"?void 0:["match","step"].includes(t)?n[0]:n[1],[r,i]=T(...s),l=Math.min(...r.flat(2)),c=Math.max(...r.flat(2));return[{name:t,getter:o,stops:s,inputs:r,outputs:i,min:l,max:c}]},V={isExpression:j,parse:M},W={collapsed:!1,toggler:!1,highlight:!1};class X{constructor(t){const{layers:n,...s}=t||{};this._options={...W,layers:void 0,...s},n&&this.addLayers(n),this._panes=d("div",{classes:"panes",styles:{display:(t==null?void 0:t.minimized)??!1?"none":"block"}}),this._minimizer=(t==null?void 0:t.minimized)!==void 0?d("button",{classes:"minimizer",events:{click:()=>{const{display:o}=this._panes.style;this._panes.style.display=o==="none"?"block":"none"}}}):void 0,this._container=d("div",{classes:["mapboxgl-ctrl","maplibregl-ctrl","mapboxgl-ctrl-legend"],content:[this._minimizer,this._panes]}),this.refresh=this.refresh.bind(this)}onAdd(t){return this._map=t,this._map.on("styledata",this.refresh),this._container}onRemove(){var t,n;(t=this._container.parentNode)==null||t.removeChild(this._container),(n=this._map)==null||n.off("styledata",this.refresh)}addLayers(t){var s,o;const n=(r,i)=>{var g;const{collapsed:l=this._options.collapsed,toggler:c=this._options.toggler,highlight:a=this._options.highlight,onToggle:h=this._options.onToggle,attributes:p}=i||{};(g=this._options.layers)==null||g.set(r,{collapsed:l,toggler:c,highlight:a,onToggle:h,attributes:p})};(s=this._options).layers??(s.layers=new Map),Array.isArray(t)?t.forEach(r=>n(r)):Object.entries(t).forEach(([r,i])=>{typeof i=="boolean"?n(r):Array.isArray(i)?n(r,{attributes:i}):n(r,i)}),(o=this._map)!=null&&o.isStyleLoaded()&&this.refresh()}removeLayers(t){t.forEach(n=>{var o;(o=this._options.layers)==null||o.delete(n);const s=this._panes.querySelector(`.mapboxgl-ctrl-legend-pane--${n}`);s&&this._panes.removeChild(s)})}_getBlocks(t,n,s,o){var a;const[r]=s.split("-").slice(-1),i=N[r];if(!i)return;const l=V.parse(o),c=((a=this._options.layers)==null?void 0:a.get(t))||this._options;return l.map(h=>i(h,n,this._map,c)).filter(Boolean)}_toggleButton(t,n){var i,l;const{onToggle:s=this._options.onToggle}=((i=this._options.layers)==null?void 0:i.get(n))||{},o=((l=this._map)==null?void 0:l.getLayoutProperty(t[0],"visibility"))||"visible",r=d("div",{classes:["toggler",`toggler--${o}`]});return r.addEventListener("click",c=>{c.preventDefault();const a=o==="none"?"visible":"none";t.forEach(h=>{var p;(p=this._map)==null||p.setLayoutProperty(h,"visibility",a),s==null||s(h,a==="visible")})}),r}refresh(){var n;const t=this._options.layers?[...this._options.layers.keys()]:void 0;(n=this._map.getStyle())==null||n.layers.filter(s=>{const o="source"in s&&s.source!=="composite",r=!t||[...t].some(i=>typeof i=="string"?s.id===i:s.id.match(i));return o&&r}).reverse().forEach(s=>{var P;const{id:o,layout:r,paint:i,metadata:l}=s,c=(t==null?void 0:t.find(_=>o.match(_)))||o,{collapsed:a,toggler:h,attributes:p}=((P=this._options.layers)==null?void 0:P.get(c))||this._options,g=Object.entries({...r,...i}).reduce((_,[z,G])=>{if(!((p==null?void 0:p.includes(z))??!0))return _;const C=this._getBlocks(c,s,z,G);return C==null||C.forEach(H=>_.push(H)),_},[]);if(!g.length)return;const f=`mapboxgl-ctrl-legend-pane--${o}`,y=this._panes.querySelector(`.${f}`),b=h?typeof h=="boolean"?[o]:h:void 0,E=(l==null?void 0:l.extraLegendClasses)??[],O=d("details",{classes:["mapboxgl-ctrl-legend-pane",f,...E],attributes:{open:y?y.getAttribute("open")!==null:!a},content:[d("summary",{content:[(l==null?void 0:l.name)||o,b&&this._toggleButton(b,c)]}),...g]});y?this._panes.replaceChild(O,y):this._panes.appendChild(O)})}}return X});