UNPKG

@2gis/mapgl-terra-draw

Version:

TerraDraw adapter for MapGL JS API

21 lines (20 loc) 18.5 kB
"use strict";var q=Object.defineProperty;var U=(o,t,e)=>t in o?q(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var f=(o,t,e)=>U(o,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const h=require("terra-draw"),b={fillColor:"#3388ff33",outlineColor:"#3388ff",outlineWidth:3,pointCap:"round"};function B(o,t="33"){const e=o.replace("#","");return e.length===3?`#${e.split("").map(r=>r+r).join("")}${t}`:e.length===6?`#${e}${t}`:o}const V=(o,t,e="round")=>{let n="";return e==="round"?n=`<circle cx="3.5" cy="3.5" r="2.5" fill="${t}" stroke="${o}" stroke-width="1.2"/>`:e==="square"?n=`<rect x="1" y="1" width="5" height="5" fill="${t}" stroke="${o}" stroke-width="1.2"/>`:n=`<circle cx="3.5" cy="3.5" r="1" fill="${o}"/>`,"data:image/svg+xml;base64,"+btoa(`<svg width="7" height="7" viewBox="0 0 7 7" fill="none" xmlns="http://www.w3.org/2000/svg"> ${n} </svg>`)};class W extends h.TerraDrawExtend.TerraDrawBaseAdapter{constructor(e){super(e);f(this,"_map");f(this,"_mapgl");f(this,"_container");f(this,"_dynamicObjects");f(this,"_style");f(this,"_drawingStyle");f(this,"featureStyles");this._mapgl=e.mapgl,this._map=e.map,this._container=this._map.getContainer(),this._dynamicObjects={},this._style={...b,...e.style},this._drawingStyle={...this._style,...e.drawingStyle},this.featureStyles={}}getLngLatFromEvent(e){const{left:n,top:r}=this._container.getBoundingClientRect(),s=e.clientX-n,i=e.clientY-r;return this.unproject(s,i)}getMapEventElement(){return this._map.getCanvas()}setDraggability(e){const n=this._map._impl;e?n.modules.handler.unblock():n.modules.handler.block()}project(e,n){const[r,s]=this._map.project([e,n]);return{x:r,y:s}}unproject(e,n){const[r,s]=this._map.unproject([e,n]);return{lng:r,lat:s}}setCursor(e){const n=this._map.getCanvas();e==="unset"?n.style.removeProperty("cursor"):n.style.cursor=e}setDoubleClickToZoom(e){const n=this._map._impl;e?n.modules.handler.unblock():n.modules.handler.block()}updateStyle(e){this._style={...this._style,...e}}updateDrawingStyle(e){this._drawingStyle={...this._drawingStyle,...e}}updateFeature(e){const n=e.id;if(!n){console.warn("Refusing attempt to process a feature without id.");return}let r=n;e.properties.selectionPoint&&(r=String(e.properties.selectionPointFeatureId)),e.properties.midPoint&&(r=String(e.properties.midPointFeatureId)),this.featureStyles[r]||(this.featureStyles[r]={...this._style});const s=e.properties.mode!==void 0,i=this.featureStyles[r]??(s?this._drawingStyle:this._style);switch(e.geometry.type){case"Polygon":{const l=this._dynamicObjects[n];l&&l.destroy(),e.properties.color||(e.properties.color=i.fillColor,e.properties.outlineColor=i.outlineColor,e.properties.outlineWidth=i.outlineWidth),this._dynamicObjects[n]=new this._mapgl.Polygon(this._map,{coordinates:e.geometry.coordinates,color:String(e.properties.color),strokeColor:String(e.properties.outlineColor),strokeWidth:Number(e.properties.outlineWidth)});break}case"LineString":{const l=this._dynamicObjects[n];l&&l.destroy(),e.properties.color||(e.properties.color=i.outlineColor,e.properties.width=i.outlineWidth),this._dynamicObjects[n]=new this._mapgl.Polyline(this._map,{coordinates:e.geometry.coordinates,color:String(e.properties.color),width:Number(e.properties.width)});break}case"Point":{const l=this._dynamicObjects[n];l&&l.destroy(),this._dynamicObjects[n]=new this._mapgl.Marker(this._map,{coordinates:e.geometry.coordinates,icon:V(i.outlineColor,e.properties.midPoint?"#ffffff":i.fillColor,i.pointCap),size:[16,16],anchor:[8,8]});break}}}render(e,n){for(const r of e.created)this.updateFeature(r);for(const r of e.updated)this.updateFeature(r);for(const r of e.deletedIds)this._dynamicObjects[r]&&(this._dynamicObjects[r].destroy(),delete this._dynamicObjects[r])}clear(){this._currentModeCallbacks&&this._currentModeCallbacks.onClear();for(const e in this._dynamicObjects){const n=this._dynamicObjects[e];n&&n.destroy(),delete this._dynamicObjects[e]}}getCoordinatePrecision(){return super.getCoordinatePrecision()}unregister(){super.unregister()}register(e){var n;super.register(e),(n=this._currentModeCallbacks)!=null&&n.onReady&&this._currentModeCallbacks.onReady()}}function R(){return[new h.TerraDrawSelectMode({projection:"web-mercator",flags:{arbitrary:{feature:{}},polygon:{feature:{draggable:!0,rotateable:!0,scaleable:!0,coordinates:{snappable:!0,midpoints:!0,draggable:!0,deletable:!0}}},freehand:{feature:{draggable:!0,coordinates:{}}},linestring:{feature:{draggable:!0,rotateable:!0,scaleable:!0,coordinates:{midpoints:!0,draggable:!0,deletable:!0}}},rectangle:{feature:{draggable:!0,coordinates:{midpoints:!1,draggable:!0,resizable:"center",deletable:!0}}},circle:{feature:{draggable:!0,coordinates:{midpoints:!1,draggable:!0,resizable:"center-fixed",deletable:!0}}},point:{feature:{draggable:!0}}}}),new h.TerraDrawPointMode({editable:!0}),new h.TerraDrawLineStringMode({snapping:{toCoordinate:!0},editable:!0}),new h.TerraDrawPolygonMode({pointerDistance:20,snapping:{toLine:!1,toCoordinate:!1},editable:!0,validation:(o,{updateType:t})=>t==="finish"||t==="commit"?h.ValidateNotSelfIntersecting(o):{valid:!0},styles:{snappingPointColor:"#ffff00"}}),new h.TerraDrawRectangleMode,new h.TerraDrawCircleMode,new h.TerraDrawFreehandMode({autoClose:!0,minDistance:10,pointerDistance:10}),new h.TerraDrawRenderMode({modeName:"arbitrary",styles:{polygonFillColor:"#4357AD",polygonOutlineColor:"#48A9A6",polygonOutlineWidth:2}}),new h.TerraDrawAngledRectangleMode,new h.TerraDrawSectorMode({}),new h.TerraDrawSensorMode]}const w=(o,t=0,e=1)=>o>e?e:o<t?t:o,u=(o,t=0,e=Math.pow(10,t))=>Math.round(e*o)/e,X=o=>Q(T(o)),T=o=>(o[0]==="#"&&(o=o.substring(1)),o.length<6?{r:parseInt(o[0]+o[0],16),g:parseInt(o[1]+o[1],16),b:parseInt(o[2]+o[2],16),a:o.length===4?u(parseInt(o[3]+o[3],16)/255,2):1}:{r:parseInt(o.substring(0,2),16),g:parseInt(o.substring(2,4),16),b:parseInt(o.substring(4,6),16),a:o.length===8?u(parseInt(o.substring(6,8),16)/255,2):1}),Y=o=>K(Z(o)),J=({h:o,s:t,v:e,a:n})=>{const r=(200-t)*e/100;return{h:u(o),s:u(r>0&&r<200?t*e/100/(r<=100?r:200-r)*100:0),l:u(r/2),a:u(n,2)}},D=o=>{const{h:t,s:e,l:n}=J(o);return`hsl(${t}, ${e}%, ${n}%)`},Z=({h:o,s:t,v:e,a:n})=>{o=o/360*6,t=t/100,e=e/100;const r=Math.floor(o),s=e*(1-t),i=e*(1-(o-r)*t),l=e*(1-(1-o+r)*t),a=r%6;return{r:u([e,i,s,s,l,e][a]*255),g:u([l,e,e,i,s,s][a]*255),b:u([s,s,l,e,e,i][a]*255),a:u(n,2)}},v=o=>{const t=o.toString(16);return t.length<2?"0"+t:t},K=({r:o,g:t,b:e,a:n})=>{const r=n<1?v(u(n*255)):"";return"#"+v(o)+v(t)+v(e)+r},Q=({r:o,g:t,b:e,a:n})=>{const r=Math.max(o,t,e),s=r-Math.min(o,t,e),i=s?r===o?(t-e)/s:r===t?2+(e-o)/s:4+(o-t)/s:0;return{h:u(60*(i<0?i+6:i)),s:u(r?s/r*100:0),v:u(r/255*100),a:n}},F=(o,t)=>{if(o===t)return!0;for(const e in o)if(o[e]!==t[e])return!1;return!0},ee=(o,t)=>o.toLowerCase()===t.toLowerCase()?!0:F(T(o),T(t)),j={},z=o=>{let t=j[o];return t||(t=document.createElement("template"),t.innerHTML=o,j[o]=t),t},O=(o,t,e)=>{o.dispatchEvent(new CustomEvent(t,{bubbles:!0,detail:e}))};let C=!1;const L=o=>"touches"in o,te=o=>C&&!L(o)?!1:(C||(C=L(o)),!0),I=(o,t)=>{const e=L(t)?t.touches[0]:t,n=o.el.getBoundingClientRect();O(o.el,"move",o.getMove({x:w((e.pageX-(n.left+window.pageXOffset))/n.width),y:w((e.pageY-(n.top+window.pageYOffset))/n.height)}))},oe=(o,t)=>{const e=t.keyCode;e>40||o.xy&&e<37||e<33||(t.preventDefault(),O(o.el,"move",o.getMove({x:e===39?.01:e===37?-.01:e===34?.05:e===33?-.05:e===35?1:e===36?-1:0,y:e===40?.01:e===38?-.01:0},!0)))};class G{constructor(t,e,n,r){const s=z(`<div role="slider" tabindex="0" part="${e}" ${n}><div part="${e}-pointer"></div></div>`);t.appendChild(s.content.cloneNode(!0));const i=t.querySelector(`[part=${e}]`);i.addEventListener("mousedown",this),i.addEventListener("touchstart",this),i.addEventListener("keydown",this),this.el=i,this.xy=r,this.nodes=[i.firstChild,i]}set dragging(t){const e=t?document.addEventListener:document.removeEventListener;e(C?"touchmove":"mousemove",this),e(C?"touchend":"mouseup",this)}handleEvent(t){switch(t.type){case"mousedown":case"touchstart":if(t.preventDefault(),!te(t)||!C&&t.button!=0)return;this.el.focus(),I(this,t),this.dragging=!0;break;case"mousemove":case"touchmove":t.preventDefault(),I(this,t);break;case"mouseup":case"touchend":this.dragging=!1;break;case"keydown":oe(this,t);break}}style(t){t.forEach((e,n)=>{for(const r in e)this.nodes[n].style.setProperty(r,e[r])})}}class ne extends G{constructor(t){super(t,"hue",'aria-label="Hue" aria-valuemin="0" aria-valuemax="360"',!1)}update({h:t}){this.h=t,this.style([{left:`${t/360*100}%`,color:D({h:t,s:100,v:100,a:1})}]),this.el.setAttribute("aria-valuenow",`${u(t)}`)}getMove(t,e){return{h:e?w(this.h+t.x*360,0,360):360*t.x}}}class re extends G{constructor(t){super(t,"saturation",'aria-label="Color"',!0)}update(t){this.hsva=t,this.style([{top:`${100-t.v}%`,left:`${t.s}%`,color:D(t)},{"background-color":D({h:t.h,s:100,v:100,a:1})}]),this.el.setAttribute("aria-valuetext",`Saturation ${u(t.s)}%, Brightness ${u(t.v)}%`)}getMove(t,e){return{s:e?w(this.hsva.s+t.x*100,0,100):t.x*100,v:e?w(this.hsva.v-t.y*100,0,100):Math.round(100-t.y*100)}}}const ie=':host{display:flex;flex-direction:column;position:relative;width:200px;height:200px;user-select:none;-webkit-user-select:none;cursor:default}:host([hidden]){display:none!important}[role=slider]{position:relative;touch-action:none;user-select:none;-webkit-user-select:none;outline:0}[role=slider]:last-child{border-radius:0 0 8px 8px}[part$=pointer]{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;display:flex;place-content:center center;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}[part$=pointer]::after{content:"";width:100%;height:100%;border-radius:inherit;background-color:currentColor}[role=slider]:focus [part$=pointer]{transform:translate(-50%,-50%) scale(1.1)}',se="[part=hue]{flex:0 0 24px;background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}[part=hue-pointer]{top:50%;z-index:2}",ae="[part=saturation]{flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(to top,#000,transparent),linear-gradient(to right,#fff,rgba(255,255,255,0));box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}[part=saturation-pointer]{z-index:3}",x=Symbol("same"),S=Symbol("color"),P=Symbol("hsva"),_=Symbol("update"),N=Symbol("parts"),H=Symbol("css"),A=Symbol("sliders");class le extends HTMLElement{static get observedAttributes(){return["color"]}get[H](){return[ie,se,ae]}get[A](){return[re,ne]}get color(){return this[S]}set color(t){if(!this[x](t)){const e=this.colorModel.toHsva(t);this[_](e),this[S]=t}}constructor(){super();const t=z(`<style>${this[H].join("")}</style>`),e=this.attachShadow({mode:"open"});e.appendChild(t.content.cloneNode(!0)),e.addEventListener("move",this),this[N]=this[A].map(n=>new n(e))}connectedCallback(){if(this.hasOwnProperty("color")){const t=this.color;delete this.color,this.color=t}else this.color||(this.color=this.colorModel.defaultColor)}attributeChangedCallback(t,e,n){const r=this.colorModel.fromAttr(n);this[x](r)||(this.color=r)}handleEvent(t){const e=this[P],n={...e,...t.detail};this[_](n);let r;!F(n,e)&&!this[x](r=this.colorModel.fromHsva(n))&&(this[S]=r,O(this,"color-changed",{value:r}))}[x](t){return this.color&&this.colorModel.equal(t,this.color)}[_](t){this[P]=t,this[N].forEach(e=>e.update(t))}}const ce={defaultColor:"#000",toHsva:X,fromHsva:({h:o,s:t,v:e})=>Y({h:o,s:t,v:e,a:1}),equal:ee,fromAttr:o=>o};class de extends le{get colorModel(){return ce}}class ue extends de{}customElements.define("hex-color-picker",ue);const k={select:{label:"Select",icon:"select"},point:{label:"Point",icon:"place"},linestring:{label:"LineString",icon:"timeline"},polygon:{label:"Polygon",icon:"pentagon"},freehand:{label:"Freehand",icon:"gesture"},circle:{label:"Circle",icon:"radio_button_unchecked"},rectangle:{label:"Rectangle",icon:"crop_din"},"angled-rectangle":{label:"Angled Rectangle",icon:"thermostat_carbon"},sector:{label:"Sector",icon:"pie_chart"},sensor:{label:"Sensor",icon:"sensors"},download:{label:"Download GeoJSON",icon:"download"},clear:{label:"Delete All",icon:"delete"},color:{label:"Color",icon:"palette"},"stroke-width":{label:"Stroke Width",icon:"line_weight"},"point-cap":{label:"Point Cap",icon:"adjust"}},pe=["select","point","linestring","polygon","freehand","circle","angled-rectangle","color","stroke-width","point-cap","download","clear"];function he(o,t,e=b){const n=document.createElement("div");n.className="terra-draw-controls";const r=t.filter(a=>["download","clear","color","stroke-width","point-cap"].indexOf(a)===-1),s=t.filter(a=>["color","stroke-width","point-cap"].indexOf(a)!==-1),i=t.filter(a=>a==="download"),l=t.filter(a=>a==="clear");if(s.length>0){const a=E("row");s.forEach(c=>{if(c==="color"){const p=me(e??b);a.appendChild(p)}else if(c==="stroke-width"){const p=ge();a.appendChild(p)}else if(c==="point-cap"){const p=fe();a.appendChild(p)}}),n.appendChild(a)}if(r.length>0){const a=E();n.appendChild(a),r.forEach(c=>{const p=k[c],y=M(p.label,p.icon,c);a.appendChild(y)})}if(i.length>0){const a=E();i.forEach(c=>{const p=k[c],y=M(p.label,p.icon,c);a.appendChild(y)}),n.appendChild(a)}if(l.length>0){const a=E();l.forEach(c=>{const p=k[c],y=M(p.label,p.icon,c);a.appendChild(y)}),n.appendChild(a)}return o.appendChild(n),n}function E(o="column"){const t=document.createElement("div");return t.classList.add("group"),t.classList.add(o),t}function M(o,t,e){const n=document.createElement("div");n.id=e,n.title=o,n.className="item";const r=document.createElement("span");return r.className="material-symbols-outlined",r.textContent=t,r.style.cssText=` font-size: 18px; line-height: 1; `,n.appendChild(r),n}function me(o){const t=document.createElement("div");t.id="color",t.className="item color-control",t.id="color",t.title="Color";const e=document.createElement("span");return e.className="color-indicator",e.style.backgroundColor=o.outlineColor,e.addEventListener("click",()=>{const n=document.createElement("div");n.classList.add("color-picker");const r=document.createElement("hex-color-picker");r.setAttribute("color",o.outlineColor),n.appendChild(r);const s=document.createElement("div");s.classList.add("color-picker-buttons"),n.appendChild(s);const i=document.createElement("button");i.textContent="Close",s.appendChild(i);const l=document.createElement("button");l.classList.add("primary"),l.textContent="Save",s.appendChild(l);let a;r.addEventListener("color-changed",c=>{a=c.detail.value}),i.addEventListener("click",()=>{document.body.removeChild(n)}),l.addEventListener("click",()=>{a&&(t.dispatchEvent(new CustomEvent("colorchange",{detail:{color:a}})),e.style.backgroundColor=a,r.setAttribute("color",o.outlineColor)),document.body.removeChild(n)}),document.body.appendChild(n)}),t.appendChild(e),t}function ge(){const o=document.createElement("div");o.className="item stroke-width-control",o.id="stroke-width",o.title="Stroke Width";const t=document.createElement("span");t.className="material-symbols-outlined",t.textContent="line_weight",t.style.cssText=` font-size: 18px; line-height: 1; `;const e=document.createElement("input");return e.type="range",e.min="1",e.max="10",e.value=b.outlineWidth.toString(),e.style.cssText=` width: 60px; margin-left: 5px; `,o.appendChild(t),o.appendChild(e),e.addEventListener("input",()=>{o.dispatchEvent(new CustomEvent("strokewidthchange",{detail:{width:parseInt(e.value)}}))}),o}function fe(){const o=document.createElement("div");o.className="item point-cap-control",o.id="point-cap",o.title="Point Cap";const t=document.createElement("span");t.className="material-symbols-outlined",t.textContent="adjust",t.style.cssText=` font-size: 18px; line-height: 1; `;const e=document.createElement("select");return e.style.cssText=` margin-left: 5px; border: 1px solid #ccc; border-radius: 2px; padding: 2px; `,[{value:"round",label:"Round"},{value:"square",label:"Square"},{value:"none",label:"None"}].forEach(r=>{const s=document.createElement("option");s.value=r.value,s.textContent=r.label,r.value===b.pointCap&&(s.selected=!0),e.appendChild(s)}),o.appendChild(t),o.appendChild(e),e.addEventListener("change",()=>{o.dispatchEvent(new CustomEvent("pointcapchange",{detail:{cap:e.value}}))}),o}function be(o,t){const e=document.createElement("a");e.setAttribute("href","data:application/json;charset=utf-8,"+encodeURIComponent(t)),e.setAttribute("download",o),e.style.display="none",document.body.appendChild(e),e.click(),document.body.removeChild(e)}function ye({map:o,mapgl:t,container:e=o.getContainer(),controls:n=pe,style:r}){const s={...b,...r},i=new W({map:o,mapgl:t,coordinatePrecision:9,style:s}),l=new h.TerraDraw({adapter:i,modes:R()}),a=he(e,n,s),c={button:void 0,mode:"static"};if(n.filter(d=>["download","clear","color","stroke-width","point-cap"].indexOf(d)===-1).forEach(d=>{const m=document.getElementById(d);m&&m.addEventListener("click",()=>{c.mode=d,l.setMode(c.mode),c.button&&c.button.classList.remove("active"),c.button=m,c.button.classList.add("active")})}),n.indexOf("color")!==-1){const d=document.getElementById("color");d&&d.addEventListener("colorchange",m=>{const g=m.detail.color,$=B(g);i.updateStyle({outlineColor:g,fillColor:$}),i.updateDrawingStyle({outlineColor:g,fillColor:$})})}if(n.indexOf("stroke-width")!==-1){const d=document.getElementById("stroke-width");d&&d.addEventListener("strokewidthchange",m=>{const g=m.detail.width;i.updateStyle({outlineWidth:g}),i.updateDrawingStyle({outlineWidth:g})})}if(n.indexOf("point-cap")!==-1){const d=document.getElementById("point-cap");d&&d.addEventListener("pointcapchange",m=>{const g=m.detail.cap;i.updateStyle({pointCap:g}),i.updateDrawingStyle({pointCap:g})})}if(n.indexOf("download")!==-1){const d=document.getElementById("download");d&&d.addEventListener("click",()=>{const m={type:"FeatureCollection",features:l.getSnapshot()};be("features.json",JSON.stringify(m,null,2))})}if(n.indexOf("clear")!==-1){const d=document.getElementById("clear");d&&d.addEventListener("click",()=>{confirm("Are you sure want to clear all features?")&&l.clear()})}return l.start(),{draw:l,cleanup:()=>{l.stop(),a.parentNode&&a.parentNode.removeChild(a)}}}exports.CONTROL_CONFIGS=k;exports.TerraDrawMapGlAdapter=W;exports.createDefaultModes=R;exports.createTerraDrawWithUI=ye;exports.defaultStyle=b;exports.makeTransparent=B;