diff --git a/src/gltf-models-placement/index.html b/src/gltf-models-placement/index.html new file mode 100644 index 0000000..3ab9857 --- /dev/null +++ b/src/gltf-models-placement/index.html @@ -0,0 +1,339 @@ + + + + + + + MapGL API - glTF models placement + + + + + +
+
+
+ + + + diff --git a/src/gltf-models-placement/index.js b/src/gltf-models-placement/index.js new file mode 100644 index 0000000..f1a449f --- /dev/null +++ b/src/gltf-models-placement/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={9958:e=>{var t,n,o=e.exports={};function a(){throw new Error("setTimeout has not been defined")}function r(){throw new Error("clearTimeout has not been defined")}function i(e){if(t===setTimeout)return setTimeout(e,0);if((t===a||!t)&&setTimeout)return t=setTimeout,setTimeout(e,0);try{return t(e,0)}catch(n){try{return t.call(null,e,0)}catch(n){return t.call(this,e,0)}}}!function(){try{t="function"==typeof setTimeout?setTimeout:a}catch(e){t=a}try{n="function"==typeof clearTimeout?clearTimeout:r}catch(e){n=r}}();var l,d=[],s=!1,u=-1;function c(){s&&l&&(s=!1,l.length?d=l.concat(d):u=-1,d.length&&m())}function m(){if(!s){var e=i(c);s=!0;for(var t=d.length;t;){for(l=d,d=[];++u1)for(var n=1;n{function e(e,t,n,o){return new(n||(n=Promise))((function(a,r){function i(e){try{d(o.next(e))}catch(e){r(e)}}function l(e){try{d(o.throw(e))}catch(e){r(e)}}function d(e){var t;e.done?a(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(i,l)}d((o=o.apply(e,t||[])).next())}))}Object.create;Object.create;let t="undefined"!=typeof Float64Array?Float64Array:Array;Math.random;Math.PI;function o(){let e=new t(3);return e[0]=0,e[1]=0,e[2]=0,e}!function(){let e=o()}();function a(){let e=new t(4);return e[0]=0,e[1]=0,e[2]=0,e[3]=0,e}!function(){let e=a()}();function r(e,t,n){return e[0]=n[0],e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=n[1],e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=n[2],e[11]=0,e[12]=t[0],e[13]=t[1],e[14]=t[2],e[15]=1,e}function i(){let e=new t(2);return e[0]=0,e[1]=0,e}function l(e,n){let o=new t(2);return o[0]=e,o[1]=n,o}!function(){let e=i()}();const d=Math.pow(2,32);Math.pow(2,20),Math.pow(2,15),Math.pow(2,16);function s(e,t){return{min:e||l(1/0,1/0),max:t||l(-1/0,-1/0)}}var u=n(9958);u.env.TEST,u.env.TEST&&location.origin,[2,5,25].map((e=>1e3*e)),Math.PI,Math.pow(2,34);const c=d/(2*Math.PI*6378137);r([],[-1,-1,0],[2,2,1]),r([],[.5,.5,0],[.5,.5,1]);function m(e){return 1/Math.cos(p(e))}s([-d/2,-d/2],[d/2,d/2]),s([-100*d/2,-d/2],[100*d/2,d/2]);i(),i();o(),o(),a(),a();function v(e,t,n){return e=Math.max(e,t),e=Math.min(e,n)}function p(e){return e*Math.PI/180}function g(t){return e(this,void 0,void 0,(function*(){const e=(new TextEncoder).encode(t),n=yield crypto.subtle.digest("SHA-1",e);return Array.from(new Uint8Array(n)).map((e=>e.toString(16).padStart(2,"0"))).join("")}))}function f(e){const t=e[0],n=e[1];return Math.sqrt(t*t+n*n)}const h={modelLocationInfo:{ru:"Для того, чтобы найти добавленную модель на карте, попробуйте подобрать подходящий масштаб, используя контролы зума или колесо мыши, а также нажать на элемент добавленной модели в панели инструментов для выставления центра карты",en:"To locate the added model on the map, try adjusting the appropriate scale using the zoom controls or the mouse wheel, and also click on the item in the added model list in the toolbar to center the map"},addModel:{ru:"Добавить модель",en:"Add model"},getSceneConfig:{ru:"Получить конфиг сцены",en:"Get scene config"},zoomRange:{ru:"Масштаб",en:"Scale"},pitchRange:{ru:"Наклон",en:"Pitch"},rotationRange:{ru:"Поворот",en:"Rotation"},modelParamCoords:{ru:"Координаты",en:"Coordinates"},modelParamCoordsInfo:{ru:"для перемещения модели используйте стрелки или ЛКМ и движение мышью",en:"to move the model, use the arrow keys or the left mouse button and mouse movement"},modelParamLng:{ru:"Долгота",en:"Longitude"},modelParamLat:{ru:"Широта",en:"Latitude"},modelParamLinkedObjects:{ru:"Связанные объекты",en:"Linked objects"},modelParamLinkedObjectsInfo:{ru:"для выбора скрытых зданий моделью кликайте на них ЛКМ",en:"to select buildings hidden by the model, click on them with the left mouse button"},modelParamLinkedIds:{ru:"ID зданий",en:"Building IDs"},modelParamRotation:{ru:"Поворот",en:"Rotation"},modelParamRotationInfo:{ru:"для поворота модели зажмите клавишу R, затем ЛКМ и подвигайте мышью",en:"to rotate the model, hold down the R key, then the left mouse button, and move the mouse"},modelParamScale:{ru:"Масштаб",en:"Scale"},modelParamScaleInfo:{ru:"для масштабирования модели зажмите клавишу S, затем ЛКМ и подвигайте мышью",en:"to scale the model, hold down the S key, then the left mouse button, and move the mouse"},pageLeaveMsg:{ru:"Вы уверены, что хотите покинуть страницу?",en:"Are you sure you want to leave the page?"},removeModelMsg:{ru:"Вы уверены, что хотите удалить модель?",en:"Are you sure you want to remove the model?"}},b=-180,y="en"!==new URL(location.href).searchParams.get("lang")?"ru":"en",L=window.map=new mapgl.Map("map",{center:[82.920412,55.030111],zoom:15,key:"a1893935-6834-4445-b97a-3405fb426c5b",enableTrackResize:!0,zoomControl:"centerRight",maxPitch:75,lowZoomMaxPitch:75,webglVersion:2,disableAntiAliasing:!1,lang:y});document.getElementById("main-wrap").innerHTML=`\n
\n
${h.modelLocationInfo[y]}
\n
\n \x3c!-- --\x3e\n \n \n
\n \n
\n
\n \n \n \n
\n
\n \n \n \n
\n
\n \n \n \n
\n
`;const x=document.getElementById("model-add-info"),w=document.getElementById("model-list"),E=document.getElementById("model-params"),F=L._impl.getContainer(),M=new Map;let C,N,S,k="idle";function I(){if(!C)return;const e=M.get(C);if(!e)return;const t=e.linkedIds.join("\n"),n=C.getCoordinates(),o=C.getRotation(),a=C.getScale(),r=E.querySelector("#lng-value");r&&(r.value=n[0].toFixed(6));const i=E.querySelector("#lat-value");i&&(i.value=n[1].toFixed(6));const l=E.querySelector("#linkedids-value");l&&(l.value=t);const d=E.querySelector("#rotate-x-value");d&&(d.value=o[0].toFixed(2));const s=E.querySelector("#rotate-y-value");s&&(s.value=o[1].toFixed(2));const u=E.querySelector("#rotate-z-value");u&&(u.value=o[2].toFixed(2));const c=E.querySelector("#scale-value");c&&(c.value=a[0].toFixed(2))}function R(){const e=[];M.forEach((({linkedIds:t})=>e.push(...t))),L.setHiddenObjects(e)}function P(){const e=[];M.forEach((({linkedIds:t})=>e.push(...t))),L.unsetHiddenObjects(e)}!function(){document.getElementById("config-button").addEventListener("click",(()=>e(this,void 0,void 0,(function*(){const e=document.createElement("a"),t=[];for(const[e,{linkedIds:n,name:o}]of M.entries()){const[a,r]=e.getCoordinates(),i=e.getRotation(),l=e.getScale(),d=yield g(`${a}${r}${n.join("")}`),s=o.match(/(.*)\.glb$/);t.push({modelId:`${s?s[1]:o}_${d}`,coordinates:[a,r],modelUrl:o,interactive:!0,rotateX:i[0],rotateY:i[1],rotateZ:i[2],scale:l[0],linkedIds:n,floors:[]})}e.href=URL.createObjectURL(new Blob([JSON.stringify(t)],{type:"application/json"})),e.download="mapgl-gltf-config.json",e.click(),URL.revokeObjectURL(e.href)}))));const t=document.getElementById("add-model-input");t.addEventListener("change",(()=>e(this,void 0,void 0,(function*(){if(!t.files)return;const e=Array.from(t.files),n=new Map;e.forEach((e=>{e.name.match(/\.glb$/)&&n.set(e.name,URL.createObjectURL(e))})),t.value="",x.style.display="none",n.forEach(((e,t)=>{const n=new mapgl.GltfModel(L,{coordinates:L.getCenter(),modelSrc:e,interactive:!0,disableAnimation:!0,hover:{color:"#0F0"},select:{color:"#00C300"}}),o=function(e,t){const n=document.createElement("div");n.classList.add("model-item"),n.classList.add("control"),n.innerHTML='';const o=()=>{e.setState({hovered:!0}),n.classList.add("hovered")},a=()=>{e.setState({hovered:!1}),n.classList.remove("hovered")},r=()=>{M.forEach((({html:e},t)=>{t.setState({selected:!1}),e.classList.remove("selected")})),e.setState({selected:!0}),n.classList.add("selected"),C=e;const t=function(e){const t=document.createElement("div");t.innerHTML=`\n
\n \n \n \n

${h.modelParamCoords[y]}

\n

${h.modelParamCoordsInfo[y]}

\n
\n \n \n
\n\n
\n \n \n
\n
\n\n
\n

${h.modelParamLinkedObjects[y]}

\n

${h.modelParamLinkedObjectsInfo[y]}

\n
\n \n \n
\n
\n\n
\n

${h.modelParamRotation[y]}

\n

${h.modelParamRotationInfo[y]}

\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n\n
\n

${h.modelParamScale[y]}

\n

${h.modelParamScaleInfo[y]}

\n
\n \n \n
\n
\n `;t.querySelector("#close-button").addEventListener("click",(t=>{t.stopPropagation(),e===C&&(M.forEach((({html:e},t)=>{t.setState({selected:!1}),e.classList.remove("selected")})),E.style.display="none",E.innerHTML="",C=void 0)}));const n=t.querySelector("#lng-value");n.addEventListener("input",(({target:t})=>{const o=parseFloat(t.value);if(Number.isNaN(o))return;n.value=String(o);const a=e.getCoordinates();e.transform([{coordinates:[o,a[1]]}])})),n.addEventListener("change",(({target:e})=>{const t=parseFloat(e.value);Number.isNaN(t)||(n.value=t.toFixed(6),n.blur())}));const o=t.querySelector("#lat-value");o.addEventListener("input",(({target:t})=>{const n=parseFloat(t.value);if(Number.isNaN(n))return;o.value=String(n);const a=e.getCoordinates();e.transform([{coordinates:[a[0],n]}])})),o.addEventListener("change",(({target:e})=>{const t=parseFloat(e.value);Number.isNaN(t)||(o.value=t.toFixed(6),o.blur())}));const a=t.querySelector("#linkedids-value");a.addEventListener("change",(({target:t})=>{const n=M.get(e);if(!n)return;const o=t.value,r=o.length?Array.from(new Set(o.split("\n").filter((e=>e.length)))):[];P(),n.linkedIds=r,R(),a.value=r.join("\n"),a.blur()}));const r=t.querySelector("#rotate-x-value");r.addEventListener("input",(({target:t})=>{let n=parseFloat(t.value);if(Number.isNaN(n))return;n%=360,r.value=String(n);const o=e.getRotation();o[0]=n,e.transform([{rotation:o}])})),r.addEventListener("change",(({target:e})=>{const t=parseFloat(e.value);Number.isNaN(t)||(r.value=t.toFixed(2),r.blur())}));const i=t.querySelector("#rotate-y-value");i.addEventListener("input",(({target:t})=>{let n=parseFloat(t.value);if(Number.isNaN(n))return;n%=360,i.value=String(n);const o=e.getRotation();o[1]=n,e.transform([{rotation:o}])})),i.addEventListener("change",(({target:e})=>{const t=parseFloat(e.value);Number.isNaN(t)||(i.value=t.toFixed(2),i.blur())}));const l=t.querySelector("#rotate-z-value");l.addEventListener("input",(({target:t})=>{let n=parseFloat(t.value);if(Number.isNaN(n))return;n%=360,l.value=String(n);const o=e.getRotation();o[2]=n,e.transform([{rotation:o}])})),l.addEventListener("change",(({target:e})=>{const t=parseFloat(e.value);Number.isNaN(t)||(l.value=t.toFixed(2),l.blur())}));const d=t.querySelector("#scale-value");return d.addEventListener("input",(({target:t})=>{const n=parseFloat(t.value);Number.isNaN(n)||(d.value=String(n),e.transform([{scale:[n,n,n]}]))})),d.addEventListener("change",(({target:e})=>{const t=parseFloat(e.value);Number.isNaN(t)||(d.value=t.toFixed(2),d.blur())})),t}(e);E.innerHTML="",E.append(t),I(),E.style.display="block"};return n.addEventListener("mouseover",o),n.addEventListener("mouseout",a),n.addEventListener("click",(()=>{r(),L.setCenter(e.getCoordinates())})),e.on("mouseover",o),e.on("mouseout",a),e.on("click",r),e.on("mousedown",(t=>{if("idle"!==k)return;const n=t.originalEvent;k="capture",N=e,F.classList.add("mapgl-capture"),S=[n.clientX,n.clientY]})),e.on("modelloaded",(()=>{n.innerHTML=`\n ${t}\n \n `;n.querySelector("svg").addEventListener("click",(t=>{t.stopPropagation();confirm(h.removeModelMsg[y])&&(e.destroy(),w.removeChild(n),e===C&&(E.style.display="none",E.innerHTML=""),w.children.length||(x.style.display="block"),P(),M.delete(e),R())}))})),w.append(n),n}(n,t);M.set(n,{html:o,name:t,linkedIds:[]})}))}))));const n=document.getElementById("zoom-value"),o=document.getElementById("zoom-range");n.min=L.getMinZoom().toFixed(2),n.max=L.getMaxZoom().toFixed(2),n.value=L.getZoom().toFixed(2),o.min=L.getMinZoom().toFixed(2),o.max=L.getMaxZoom().toFixed(2),o.value=L.getZoom().toFixed(2),n.addEventListener("change",(e=>{const t=e.target;let a=parseFloat(t.value);Number.isNaN(a)||(a=v(a,L.getMinZoom(),L.getMaxZoom()),n.value=a.toFixed(2),o.value=a.toFixed(2),L.setZoom(a))})),o.addEventListener("input",(e=>{const t=e.target,o=parseFloat(t.value);Number.isNaN(o)||(n.value=o.toFixed(2),L.setZoom(o))})),L.on("zoom",(({isUser:e})=>{if(!e)return;const t=Math.round(100*L.getZoom())/100;n.value=t.toFixed(2),o.value=t.toFixed(2)}));const a=document.getElementById("pitch-value"),r=document.getElementById("pitch-range");a.min=(0).toFixed(2),a.max=75..toFixed(2),a.value=L.getPitch().toFixed(2),r.min=(0).toFixed(2),r.max=75..toFixed(2),r.value=L.getPitch().toFixed(2),a.addEventListener("change",(e=>{const t=e.target;let n=parseFloat(t.value);Number.isNaN(n)||(n=v(n,0,75),a.value=n.toFixed(2),r.value=n.toFixed(2),L.setPitch(n))})),r.addEventListener("input",(e=>{const t=e.target,n=parseFloat(t.value);Number.isNaN(n)||(a.value=n.toFixed(2),L.setPitch(n))})),L.on("pitch",(({isUser:e})=>{if(!e)return;const t=Math.round(100*L.getPitch())/100;a.value=t.toFixed(2),r.value=t.toFixed(2)}));const i=document.getElementById("rotation-value"),l=document.getElementById("rotation-range");i.min=b.toFixed(2),i.max=180..toFixed(2),i.value=L.getRotation().toFixed(2),l.min=b.toFixed(2),l.max=180..toFixed(2),l.value=L.getRotation().toFixed(2),i.addEventListener("change",(e=>{const t=e.target;let n=parseFloat(t.value);Number.isNaN(n)||(n=v(n,b,180),i.value=n.toFixed(2),l.value=n.toFixed(2),L.setRotation(n))})),l.addEventListener("input",(e=>{const t=e.target,n=parseFloat(t.value);Number.isNaN(n)||(i.value=n.toFixed(2),L.setRotation(n))})),L.on("rotation",(({isUser:e})=>{if(!e)return;const t=Math.round(100*L.getRotation())/100;i.value=t.toFixed(2),l.value=t.toFixed(2)}))}(),function(){window.addEventListener("beforeunload",(e=>{const t=h.pageLeaveMsg[y];return e.returnValue=t,t})),window.addEventListener("keydown",(({code:e})=>{"Escape"===e&&"idle"===k&&(M.forEach((({html:e},t)=>{t.setState({selected:!1}),e.classList.remove("selected")})),E.style.display="none",E.innerHTML="",C=void 0)}));const e={ArrowUp:[0,1],ArrowDown:[0,-1],ArrowRight:[1,0],ArrowLeft:[-1,0]};let t;window.addEventListener("keydown",(({code:t})=>{if("idle"!==k)return;if(!C)return;if(!Object.keys(e).includes(t))return;if(Boolean(E.querySelectorAll("*:focus").length))return;const n=L.getRotation(),o=function(e,t){return[e[0]*Math.cos(t)-e[1]*Math.sin(t),e[0]*Math.sin(t)+e[1]*Math.cos(t)]}(e[t],p(n)),a=C.getCoordinates(),r=mapgl._J.utils.projectGeoToMap(a),i=.1*c*m(a[1]);r[0]+=o[0]*i,r[1]+=o[1]*i,C.transform([{coordinates:mapgl._J.utils.projectMapToGeo(r)}]),I()}));const n=e=>{if("scale"===k||"rotation"===k){if(e instanceof KeyboardEvent){if("KeyS"!==e.code&&"KeyR"!==e.code)return;if("rotation"===k&&"KeyS"===e.code)return;if("scale"===k&&"KeyR"===e.code)return}L._impl.modules.handler.unblock(),F.classList.remove("mapgl-scale","mapgl-rotate"),t=void 0,S=void 0,k="idle"}};window.addEventListener("keyup",n),window.addEventListener("mouseleave",n),window.addEventListener("keydown",(({code:e})=>{if("idle"!==k||!C)return;return Boolean(E.querySelectorAll("*:focus").length)||"KeyS"!==e&&"KeyR"!==e?void 0:(L._impl.modules.handler.block(),"KeyS"===e?(F.classList.add("mapgl-scale"),void(k="scale")):"KeyR"===e?(F.classList.add("mapgl-rotate"),void(k="rotation")):void 0)})),window.addEventListener("mousemove",(e=>{if("scale"!==k&&"rotation"!==k)return;if(!C)return;if(1!==e.buttons)return;if(!S||!t)return S=[e.clientX,e.clientY],void(t=C.getScale());const n=[e.clientX,e.clientY],o=L.project(C.getCoordinates()),a=[S[0]-o[0],S[1]-o[1]],r=[n[0]-o[0],n[1]-o[1]],i=f(a),l=f(r);if(i&&l){if("scale"===k){if(!t)return;C.transform([{scale:t.map((e=>Math.max(l*e/i,.01)))}])}else if("rotation"===k){const e=Math.sign((s=r,(d=a)[0]*s[1]-d[1]*s[0])),t=C.getRotation(),o=Math.acos(v(function(e,t){return e[0]*t[0]+e[1]*t[1]}(a.map((e=>e/i)),r.map((e=>e/l))),-1,1));t[2]+=Math.round(-e*(o/Math.PI*180)*.5%360*100)/100,C.transform([{rotation:t}]),S=n}var d,s;I()}})),window.addEventListener("mouseup",(({button:e})=>{"scale"!==k&&"rotation"!==k||0===e&&(t=void 0,S=void 0)})),L._impl.on("click",(({target:e})=>{if("idle"!==k||!e||!C)return;const{symbol:t}=e;if("polygonExtrusion"!==t&&"buildingModel"!==t&&"gltfModel"!==t)return;const n=M.get(C);n&&(n.linkedIds.includes(e.id)?L.triggerRerender():(n.linkedIds.push(e.id),R(),I()))}));const o=()=>{"capture"===k&&(L._impl.modules.handler.unblock(),S=void 0,k="idle",N=void 0,F.classList.remove("mapgl-capture"))};window.addEventListener("mouseup",o),window.addEventListener("mouseleave",o),window.addEventListener("mousemove",(e=>{if("capture"!==k||!S||!N)return;L._impl.modules.handler.block();const t=[e.clientX,e.clientY],n=L.project(N.getCoordinates()),o=[t[0]-S[0],t[1]-S[1]];N.transform([{coordinates:L.unproject([n[0]+o[0],n[1]+o[1]])}]),S=t,N===C&&I()}))}()})()})(); \ No newline at end of file diff --git a/src/gltf-models-placement/preview.png b/src/gltf-models-placement/preview.png new file mode 100644 index 0000000..981954a Binary files /dev/null and b/src/gltf-models-placement/preview.png differ