From c6a66b321d34f7a56561af4dad6e17a1b29b3ff1 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 10 May 2026 00:33:41 +0300 Subject: [PATCH 01/21] chore: add examples --- .dockerignore | 1 + .gitignore | 1 + examples/cesium-3d/3d-model.js | 52 ++ examples/cesium-3d/cesium.html | 1 + examples/cesium-geocoding/cesium.html | 1 + examples/cesium-geocoding/cesium.js | 71 ++ examples/cesium-layers-split/split-layers.css | 14 + .../cesium-layers-split/split-layers.html | 4 + examples/cesium-layers-split/split-layers.js | 78 ++ examples/cesium-terrain/cesium.html | 1 + examples/cesium-terrain/cesium.js | 50 ++ examples/cesium-viewshed/viewshed.css | 0 examples/cesium-viewshed/viewshed.html | 1 + examples/cesium-viewshed/viewshed.js | 722 ++++++++++++++++++ examples/cesium-wmts/cesium.html | 1 + examples/cesium-wmts/cesium.js | 18 + examples/cesium.html | 1 + examples/cesium.js | 16 + examples/cesium_basic.js | 15 + examples/cesium_wmts.js | 15 + examples/config/3d-config.js | 3 + examples/config/common-config.js | 4 + examples/config/dem-config.js | 3 + examples/config/raster-config.js | 8 + examples/config/vector-config.js | 4 + examples/index.json | 209 +++++ examples/leaflet-wmts/leaflet.css | 3 + examples/leaflet-wmts/leaflet.html | 1 + examples/leaflet-wmts/wmts.js | 15 + examples/leaflet.css | 3 + examples/leaflet.html | 1 + examples/leaflet_basic.js | 7 + examples/markdown.md | 30 + examples/ol-ext-example/ol-ext.js | 27 + examples/ol-ext-example/openlayers.css | 6 + examples/ol-ext-example/openlayers.html | 1 + .../box-selection.html | 13 + .../openlayers-box-selection/box-selection.js | 157 ++++ .../openlayers-box-selection/openlayers.css | 6 + .../openlayers-debug-layer/debug-layer.js | 38 + .../openlayers-debug-layer/openlayers.css | 6 + .../openlayers-debug-layer/openlayers.html | 1 + .../draw-and-modify.css | 7 + .../draw-and-modify.html | 16 + .../draw-and-modify.js | 192 +++++ .../openlayers-overview-map/overview-map.css | 40 + .../openlayers-overview-map/overview-map.html | 1 + .../openlayers-overview-map/overview-map.js | 38 + examples/openlayers-permalink/permalink.css | 7 + examples/openlayers-permalink/permalink.html | 3 + examples/openlayers-permalink/permalink.js | 85 +++ examples/openlayers-preload/preload.css | 6 + examples/openlayers-preload/preload.html | 2 + examples/openlayers-preload/preload.js | 35 + .../openlayers-query-service/openlayers.css | 6 + .../openlayers-query-service/openlayers.html | 1 + .../openlayers-query-service/query-service.js | 53 ++ .../interactive-sensitive.js | 92 +++ examples/openlayers-sensitive/openlayers.css | 6 + examples/openlayers-sensitive/openlayers.html | 8 + .../street-labels.css | 7 + .../street-labels.html | 1 + .../openlayers-street-labels/street-labels.js | 70 ++ examples/openlayers-wmts/openlayers.css | 6 + examples/openlayers-wmts/openlayers.html | 1 + examples/openlayers-wmts/wmts.js | 27 + examples/openlayers.css | 6 + examples/openlayers.html | 1 + examples/openlayers_basic.js | 5 + examples/openlayers_geojson.js | 241 ++++++ package-lock.json | 372 +++++++++ package.json | 3 +- scripts/upload-examples.sh | 142 ++++ 73 files changed, 3088 insertions(+), 1 deletion(-) create mode 100644 examples/cesium-3d/3d-model.js create mode 100644 examples/cesium-3d/cesium.html create mode 100644 examples/cesium-geocoding/cesium.html create mode 100644 examples/cesium-geocoding/cesium.js create mode 100644 examples/cesium-layers-split/split-layers.css create mode 100644 examples/cesium-layers-split/split-layers.html create mode 100644 examples/cesium-layers-split/split-layers.js create mode 100644 examples/cesium-terrain/cesium.html create mode 100644 examples/cesium-terrain/cesium.js create mode 100644 examples/cesium-viewshed/viewshed.css create mode 100644 examples/cesium-viewshed/viewshed.html create mode 100644 examples/cesium-viewshed/viewshed.js create mode 100644 examples/cesium-wmts/cesium.html create mode 100644 examples/cesium-wmts/cesium.js create mode 100644 examples/cesium.html create mode 100644 examples/cesium.js create mode 100644 examples/cesium_basic.js create mode 100644 examples/cesium_wmts.js create mode 100644 examples/config/3d-config.js create mode 100644 examples/config/common-config.js create mode 100644 examples/config/dem-config.js create mode 100644 examples/config/raster-config.js create mode 100644 examples/config/vector-config.js create mode 100644 examples/index.json create mode 100644 examples/leaflet-wmts/leaflet.css create mode 100644 examples/leaflet-wmts/leaflet.html create mode 100644 examples/leaflet-wmts/wmts.js create mode 100644 examples/leaflet.css create mode 100644 examples/leaflet.html create mode 100644 examples/leaflet_basic.js create mode 100644 examples/markdown.md create mode 100644 examples/ol-ext-example/ol-ext.js create mode 100644 examples/ol-ext-example/openlayers.css create mode 100644 examples/ol-ext-example/openlayers.html create mode 100644 examples/openlayers-box-selection/box-selection.html create mode 100644 examples/openlayers-box-selection/box-selection.js create mode 100644 examples/openlayers-box-selection/openlayers.css create mode 100644 examples/openlayers-debug-layer/debug-layer.js create mode 100644 examples/openlayers-debug-layer/openlayers.css create mode 100644 examples/openlayers-debug-layer/openlayers.html create mode 100644 examples/openlayers-draw-and-modify/draw-and-modify.css create mode 100644 examples/openlayers-draw-and-modify/draw-and-modify.html create mode 100644 examples/openlayers-draw-and-modify/draw-and-modify.js create mode 100644 examples/openlayers-overview-map/overview-map.css create mode 100644 examples/openlayers-overview-map/overview-map.html create mode 100644 examples/openlayers-overview-map/overview-map.js create mode 100644 examples/openlayers-permalink/permalink.css create mode 100644 examples/openlayers-permalink/permalink.html create mode 100644 examples/openlayers-permalink/permalink.js create mode 100644 examples/openlayers-preload/preload.css create mode 100644 examples/openlayers-preload/preload.html create mode 100644 examples/openlayers-preload/preload.js create mode 100644 examples/openlayers-query-service/openlayers.css create mode 100644 examples/openlayers-query-service/openlayers.html create mode 100644 examples/openlayers-query-service/query-service.js create mode 100644 examples/openlayers-sensitive/interactive-sensitive.js create mode 100644 examples/openlayers-sensitive/openlayers.css create mode 100644 examples/openlayers-sensitive/openlayers.html create mode 100644 examples/openlayers-street-labels/street-labels.css create mode 100644 examples/openlayers-street-labels/street-labels.html create mode 100644 examples/openlayers-street-labels/street-labels.js create mode 100644 examples/openlayers-wmts/openlayers.css create mode 100644 examples/openlayers-wmts/openlayers.html create mode 100644 examples/openlayers-wmts/wmts.js create mode 100644 examples/openlayers.css create mode 100644 examples/openlayers.html create mode 100644 examples/openlayers_basic.js create mode 100644 examples/openlayers_geojson.js create mode 100755 scripts/upload-examples.sh diff --git a/.dockerignore b/.dockerignore index fc409a8..8687cf3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -7,3 +7,4 @@ node_modules !.env.example vite.config.js.timestamp-* vite.config.ts.timestamp-* +examples/ diff --git a/.gitignore b/.gitignore index 6635cf5..08bef08 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ node_modules !.env.example vite.config.js.timestamp-* vite.config.ts.timestamp-* +examples/assets/ diff --git a/examples/cesium-3d/3d-model.js b/examples/cesium-3d/3d-model.js new file mode 100644 index 0000000..d033004 --- /dev/null +++ b/examples/cesium-3d/3d-model.js @@ -0,0 +1,52 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { DEM_URL } from './config/dem-config.js'; +import { MODEL_3D_URL } from './config/3d-config.js'; + +const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() + }), + terrainProvider: new Cesium.CesiumTerrainProvider({ + url: new Cesium.Resource({ + url: DEM_URL, + queryParameters: { + token: TOKEN + } + }) + }), +}); + +viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ + url: new Cesium.Resource({ + url: MODEL_3D_URL, + queryParameters: { + token: TOKEN + } + }), + maximumScreenSpaceError: 5, + cullRequestsWhileMovingMultiplier: 120, + preloadFlightDestination: true, + preferLeaves: true, + skipLevelOfDetail: true +})); + + +viewer.camera.flyTo({ + destination: Cesium.Cartesian3.fromDegrees(35.201436, 33.265378, 300), + orientation: { + heading: Cesium.Math.toRadians(25.0), + pitch: Cesium.Math.toRadians(-10.0), + roll: 0.0 + } +}); diff --git a/examples/cesium-3d/cesium.html b/examples/cesium-3d/cesium.html new file mode 100644 index 0000000..95872da --- /dev/null +++ b/examples/cesium-3d/cesium.html @@ -0,0 +1 @@ +
diff --git a/examples/cesium-geocoding/cesium.html b/examples/cesium-geocoding/cesium.html new file mode 100644 index 0000000..95872da --- /dev/null +++ b/examples/cesium-geocoding/cesium.html @@ -0,0 +1 @@ +
diff --git a/examples/cesium-geocoding/cesium.js b/examples/cesium-geocoding/cesium.js new file mode 100644 index 0000000..bc11fba --- /dev/null +++ b/examples/cesium-geocoding/cesium.js @@ -0,0 +1,71 @@ +'use strict'; +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { GEOCODING_URL } from './config/vector-config.js'; + +//Sandcastle_Begin +/** + * This class is an example of a custom geocoder. It provides geocoding through the OpenStreetMap Nominatim service. + * @alias OpenStreetMapNominatimGeocoder + * @constructor + */ +function OpenStreetMapNominatimGeocoder() {} + +/** + * The function called to geocode using this geocoder service. + * + * @param {String} input The query to be sent to the geocoder service + * @returns {Promise} + */ +OpenStreetMapNominatimGeocoder.prototype.geocode = function (input) { + const resource = new Cesium.Resource({ + url: GEOCODING_URL, + queryParameters: { + format: "json", + q: input, + token: TOKEN + }, + headers: { + "accept-language": "he" + } + }); + + return resource.fetchJson().then(function (results) { + let bboxDegrees; + return results.map(function (resultObject) { + bboxDegrees = resultObject.boundingbox; + return { + displayName: resultObject.display_name, + destination: Cesium.Rectangle.fromDegrees( + bboxDegrees[2], + bboxDegrees[0], + bboxDegrees[3], + bboxDegrees[1] + ), + }; + }); + }); +}; + +const viewer = new Cesium.Viewer("cesiumContainer", { + vrButton: false, + homeButton: false, + infoBox: false, + timeline: false, + navigationHelpButton: false, + shouldAnimate: false, + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() + }), + geocoder: new OpenStreetMapNominatimGeocoder(), +}); diff --git a/examples/cesium-layers-split/split-layers.css b/examples/cesium-layers-split/split-layers.css new file mode 100644 index 0000000..b55d1ea --- /dev/null +++ b/examples/cesium-layers-split/split-layers.css @@ -0,0 +1,14 @@ + +#slider { + position: absolute; + left: 50%; + top: 0px; + background-color: #d3d3d3; + width: 5px; + height: 100%; + z-index: 9999; +} + +#slider:hover { + cursor: ew-resize; +} \ No newline at end of file diff --git a/examples/cesium-layers-split/split-layers.html b/examples/cesium-layers-split/split-layers.html new file mode 100644 index 0000000..faaf4ac --- /dev/null +++ b/examples/cesium-layers-split/split-layers.html @@ -0,0 +1,4 @@ +
+
+
+
\ No newline at end of file diff --git a/examples/cesium-layers-split/split-layers.js b/examples/cesium-layers-split/split-layers.js new file mode 100644 index 0000000..e12f390 --- /dev/null +++ b/examples/cesium-layers-split/split-layers.js @@ -0,0 +1,78 @@ +"use strict"; +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; + +const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() + }), + baseLayerPicker: false, + infoBox: false, +}); + +const layers = viewer.imageryLayers; +const secondLayer = layers.addImageryProvider( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: "OSM-RasterVectorBest", + style: "default", + format: "image/png", + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() + }), +); +secondLayer.splitDirection = Cesium.SplitDirection.LEFT; // Only show to the left of the slider. + +// Sync the position of the slider with the split position +const slider = document.getElementById("slider"); +viewer.scene.splitPosition = + slider.offsetLeft / slider.parentElement.offsetWidth; + +const handler = new Cesium.ScreenSpaceEventHandler(slider); + +let moveActive = false; + +function move(movement) { + if (!moveActive) { + return; + } + + const relativeOffset = movement.endPosition.x; + const splitPosition = + (slider.offsetLeft + relativeOffset) / + slider.parentElement.offsetWidth; + slider.style.left = `${100.0 * splitPosition}%`; + viewer.scene.splitPosition = splitPosition; +} + +handler.setInputAction(function () { + moveActive = true; +}, Cesium.ScreenSpaceEventType.LEFT_DOWN); +handler.setInputAction(function () { + moveActive = true; +}, Cesium.ScreenSpaceEventType.PINCH_START); + +handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE); +handler.setInputAction(move, Cesium.ScreenSpaceEventType.PINCH_MOVE); + +handler.setInputAction(function () { + moveActive = false; +}, Cesium.ScreenSpaceEventType.LEFT_UP); +handler.setInputAction(function () { + moveActive = false; +}, Cesium.ScreenSpaceEventType.PINCH_END); diff --git a/examples/cesium-terrain/cesium.html b/examples/cesium-terrain/cesium.html new file mode 100644 index 0000000..95872da --- /dev/null +++ b/examples/cesium-terrain/cesium.html @@ -0,0 +1 @@ +
diff --git a/examples/cesium-terrain/cesium.js b/examples/cesium-terrain/cesium.js new file mode 100644 index 0000000..caf717a --- /dev/null +++ b/examples/cesium-terrain/cesium.js @@ -0,0 +1,50 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { DEM_URL } from './config/dem-config.js'; + +const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "newGrids", + tilingScheme: new Cesium.GeographicTilingScheme() + }), + terrainProvider: new Cesium.CesiumTerrainProvider({ + url: new Cesium.Resource({ + url: DEM_URL, + queryParameters: { + token: TOKEN + } + }) + }) +}); + +viewer.camera.flyTo({ + destination: Cesium.Cartesian3.fromDegrees(35.567306, 33.210784, 6000), + orientation: { + heading: Cesium.Math.toRadians(25.0), + pitch: Cesium.Math.toRadians(-10.0), + roll: 0.0 + } +}); + +viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: "WORLD_MAP_BASE_THIN-RasterVectorBest", + style: "default", + format: "image/png", + tileMatrixSetID: "newGrids", + tilingScheme: new Cesium.GeographicTilingScheme() + })); diff --git a/examples/cesium-viewshed/viewshed.css b/examples/cesium-viewshed/viewshed.css new file mode 100644 index 0000000..e69de29 diff --git a/examples/cesium-viewshed/viewshed.html b/examples/cesium-viewshed/viewshed.html new file mode 100644 index 0000000..6deed9d --- /dev/null +++ b/examples/cesium-viewshed/viewshed.html @@ -0,0 +1 @@ +
diff --git a/examples/cesium-viewshed/viewshed.js b/examples/cesium-viewshed/viewshed.js new file mode 100644 index 0000000..8d46547 --- /dev/null +++ b/examples/cesium-viewshed/viewshed.js @@ -0,0 +1,722 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { DEM_URL } from './config/dem-config.js'; +import { MODEL_3D_URL } from './config/3d-config.js'; + +const fsShaderText = ` +#define USE_NORMAL_SHADING +uniform float view_distance; // Maximum distance for shadow effect +uniform vec3 viewArea_color; // Color for visible areas +uniform vec3 shadowArea_color; // Color for invisible areas +uniform float percentShade; // Mix number for color blending +uniform sampler2D colorTexture; // Texture for color +uniform sampler2D shadowMap; // Shadow map texture +uniform sampler2D depthTexture; // Depth texture +uniform mat4 shadowMap_matrix; // Shadow map matrix +uniform vec3 viewPosition_WC; // Uniform for view position +uniform vec3 cameraPosition_WC; // Uniform for camera position +uniform vec4 shadowMap_camera_positionEC; // Light position in eye coordinates +uniform vec4 shadowMap_camera_directionEC; // Light direction in eye coordinates +uniform vec3 ellipsoidInverseRadii; +uniform vec3 shadowMap_camera_up; // Light up direction +uniform vec3 shadowMap_camera_dir; // Light direction +uniform vec3 shadowMap_camera_right; // Light right direction +uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness; // Shadow map parameters +uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth; // Shadow map parameters +uniform vec4 _shadowMap_cascadeSplits[2]; +uniform mat4 _shadowMap_cascadeMatrices[4]; +uniform vec4 _shadowMap_cascadeDistances; +uniform bool exclude_terrain; + +in vec2 v_textureCoordinates; +out vec4 FragColor; + +vec4 toEye(in vec2 uv, in float depth){ + float x = uv.x * 2.0 - 1.0; + float y = uv.y * 2.0 - 1.0; + vec4 camPosition = czm_inverseProjection * vec4(x, y, depth, 1.0); + float reciprocalW = 1.0 / camPosition.w; + camPosition *= reciprocalW; + return camPosition; +} + +// This function gets the depth from a depth texture. +float getDepth(in vec4 depth){ + // Unpack the depth value from the depth texture + float z_window = czm_unpackDepth(depth); + // Reverse the logarithmic depth value to get the linear depth + z_window = czm_reverseLogDepth(z_window); + // Get the near and far values of the depth range + float n_range = czm_depthRange.near; + float f_range = czm_depthRange.far; + // Convert the depth value from window coordinates to normalized device coordinates + return (2.0 * z_window - n_range - f_range) / (f_range - n_range); +} + +/** + * Projects a point onto a plane. + * + * @param planeNormal - A vector representing the normal of the plane. + * @param planeOrigin - A point on the plane. + * @param point - The point to be projected onto the plane. + * @return The projection of the point on the plane. + */ +vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point){ + // Calculate the vector from the plane origin to the point + vec3 v01 = point - planeOrigin; + + // Calculate the perpendicular distance from the point to the plane + float d = dot(planeNormal, v01); + + // Subtract the product of the plane normal and d from the point + // to get the projection of the point on the plane + return (point - planeNormal * d); +} + +/** + * Calculates the magnitude (length) of a vector. + * + * @param pt - The input vector. + * @return The magnitude of the vector. + */ +float point2mag(vec3 point){ + // Square each component of the vector, add them together, + // and take the square root of the result + return sqrt(point.x*point.x + point.y*point.y + point.z*point.z); +} + +/** + * Main function for the fragment shader. + */ +void main() +{ + // Get the color and depth at the current texture coordinates + vec4 color = texture(colorTexture, v_textureCoordinates); + vec4 cDepth = texture(depthTexture, v_textureCoordinates); + + // Get the depth and position in eye coordinates + float depth = getDepth(cDepth); + vec4 positionEC = toEye(v_textureCoordinates, depth); + + // If the depth is at its maximum value, set the fragment color to the texture color and return + if(cDepth.r >= 1.0){ + FragColor = color; + return; + } + + //check to see if we are within distance of the view target + float cameraDistance = length(cameraPosition_WC.xyz - viewPosition_WC.xyz); + + // Get the fragment position in world coordinates + vec4 fragPosition_WC = vec4(v_textureCoordinates, 0.0, 1.0); + + if ( + cDepth.r >= 1.0 || + (exclude_terrain && czm_ellipsoidContainsPoint(ellipsoidInverseRadii, positionEC.xyz)) + ){ + FragColor = color; + return; + } + + // Initialize shadow parameters + czm_shadowParameters shadowParameters; + shadowParameters.texelStepSize = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy; + shadowParameters.depthBias = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z; + shadowParameters.normalShadingSmooth = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w; + shadowParameters.darkness = shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w; + + // Adjust the depth bias + shadowParameters.depthBias *= max(depth * 0.01, 1.0); + + // Calculate the direction in eye coordinates + vec3 directionEC = normalize(positionEC.xyz - shadowMap_camera_positionEC.xyz); + + // Calculate the dot product of the normal and the negative direction + float nDotL = clamp(dot(vec3(1.0), -directionEC), 0.0, 1.0); + + // Calculate the shadow position + vec4 shadowPosition = shadowMap_matrix * positionEC; + shadowPosition /= shadowPosition.w; + + // If the shadow position is outside the [0, 1] range in any dimension, set the fragment color to the texture color and return + if (any(lessThan(shadowPosition.xyz, vec3(0.0))) || any(greaterThan(shadowPosition.xyz, vec3(1.0)))) + { + FragColor = color; + return; + } + + // If the distance between the coordinates and the viewpoint is greater than the maximum distance, the shadow effect is discarded + vec4 lw = czm_inverseView* vec4(shadowMap_camera_positionEC.xyz, 1.0); + vec4 vw = czm_inverseView* vec4(positionEC.xyz, 1.0); + + if(distance(lw.xyz,vw.xyz)>view_distance){ + FragColor = color; + return; + } + + // Set the shadow parameters + shadowParameters.texCoords = shadowPosition.xy; + shadowParameters.depth = shadowPosition.z; + shadowParameters.nDotL = nDotL; + + // Calculate the shadow visibility + float visibility = czm_shadowVisibility(shadowMap, shadowParameters); + + // If the visibility is 1.0, mix the color with the visible color + if(visibility==1.0){ + FragColor = mix(texture(colorTexture, v_textureCoordinates),vec4(viewArea_color,1.0),percentShade); + }else{ + if(abs(shadowPosition.z-0.0)<0.01){ + FragColor = color; + return; + } + FragColor = mix(texture(colorTexture, v_textureCoordinates),vec4(shadowArea_color,1.0),percentShade); + } +}`; +const fsShader = fsShaderText.replace("`;",""); +//https://github.com/DigitalArsenal/SensorShadow +const { + ShadowMap, + PerspectiveFrustum, + Camera, + Color, + defaultValue, + PositionProperty, + ConstantPositionProperty, + Cartesian2, + Cartesian3, + Cartesian4, + EllipsoidTerrainProvider, + PostProcessStage, + Math : CesiumMath +} = Cesium; + +const defaultValues = { + cameraPosition: new ConstantPositionProperty(), + viewPosition: new ConstantPositionProperty(), + viewAreaColor: new Color(0, 1, 0), + shadowAreaColor: new Color(1, 0, 0), + alpha: 0.5, + frustum: true, + size: 4096, + depthBias: 2e-12, +}; + +/** + * SensorShadow Class. + * This class handles the creation, update and management of sensor shadow entities. + * + * @property {Object} viewer - A reference to the Cesium viewer instance. + * @property {ConstantPositionProperty|PositionProperty|Cartesian3} cameraPosition - The camera position. + * @property {ConstantPositionProperty|PositionProperty|Cartesian3} viewPosition - The view position. + * @property {Color} viewAreaColor - The color of the visible area of the sensor shadow. + * @property {Color} shadowAreaColor - The color of the hidden area of the sensor shadow. + * @property {number} alpha - The alpha value for the sensor shadow. + * @property {boolean} frustum - Whether the frustum is enabled. + * @property {number} size - The size of the sensor shadow. + * @property {function|null} preUpdateListener - A pre-update listener function. + */ +class SensorShadow { + /** + * Constructs a new SensorShadow instance. + * + * @param {Object} viewer - A reference to the Cesium viewer instance. + * @param {Object} options - An optional configuration object. + * + * @example + * let sensorShadow = new SensorShadow(viewer, { + * cameraPosition: new Cartesian3(0, 0, 0), + * viewPosition: new Cartesian3(1, 1, 1), + * viewAreaColor: new Color(0, 1, 0), + * shadowAreaColor: new Color(1, 0, 0), + * alpha: 0.5, + * frustum: true, + * size: 512 + * }); + */ + constructor(viewer, options = {}) { + this.viewer = viewer; + + this.cameraPosition = + typeof options.cameraPosition.getValue === "function" + ? options.cameraPosition + : new ConstantPositionProperty(options.cameraPosition); + + this.viewPosition = + typeof options.viewPosition.getValue === "function" + ? options.viewPosition + : new ConstantPositionProperty(options.viewPosition); + + this.viewAreaColor = defaultValue( + options.viewAreaColor, + defaultValues.viewAreaColor + ); + + this.shadowAreaColor = defaultValue( + options.shadowAreaColor, + defaultValues.shadowAreaColor + ); + + this.alpha = defaultValue(options.alpha, defaultValues.alpha); + this.size = defaultValue(options.size, defaultValues.size); + this.frustum = defaultValue(options.frustum, defaultValues.frustum); + this.depthBias = defaultValue(options.depthBias, defaultValues.depthBias); + + this.preUpdateListener = null; + + if (this.cameraPosition && this.viewPosition) { + this._addToScene(); + } + } + + /** + * Get the actual position of the camera. + * This method calculates the position vector based on the current time. + * + * @private + * @returns {Cartesian3} The calculated camera position vector. + */ + get _getVectors() { + let positionVector = this.cameraPosition.getValue( + this.viewer.clock.currentTime + ); + let viewVector = this.viewPosition.getValue(this.viewer.clock.currentTime); + let distanceBetweenVectors = Number( + Cartesian3.distance(viewVector, positionVector).toFixed(1) + ); + + if (distanceBetweenVectors > 10000) { + let multiple = 1 - 10000 / distanceBetweenVectors; + positionVector = Cartesian3.lerp( + positionVector, + viewVector, + multiple, + new Cartesian3() + ); + } + + return { positionVector, viewVector }; + } + + /** + * Adds the SensorShadow to the scene. + * + * @private + */ + _addToScene() { + this._createShadowMap(); + this._addPostProcess(); + this.viewer.scene.primitives.add(this); + + } + + /** + * Creates the shadow map. + * + * @private + */ + _createShadowMap(updateOnly) { + let { positionVector, viewVector } = this._getVectors; + + const distance = Number( + Cartesian3.distance(viewVector, positionVector).toFixed(1) + ); + + if (distance > 10000) { + const multiple = 1 - 10000 / distance; + positionVector = Cartesian3.lerp( + positionVector, + viewVector, + multiple, + new Cartesian3() + ); + } + + const scene = this.viewer.scene; + + const camera = new Camera(scene); + + camera.position = positionVector; + + camera.direction = Cartesian3.subtract( + viewVector, + positionVector, + new Cartesian3(0, 0, 0) + ); + + camera.up = Cartesian3.normalize(positionVector, new Cartesian3(0, 0, 0)); + + camera.frustum = new PerspectiveFrustum({ + fov: CesiumMath.toRadians(120), + aspectRatio: scene.canvas.clientWidth / scene.canvas.clientHeight, + near: 0.1, + far: distance, + }); + + if (!updateOnly) { + this.viewShadowMap = new ShadowMap({ + lightCamera: camera, + enable: true, + isPointLight: false, + isSpotLight: true, + cascadesEnabled: false, + context: scene.context, + size: this.size, + pointLightRadius: distance, + fromLightSource: false, + maximumDistance: distance, + }); + } else { + this.viewShadowMap._lightCamera.position = positionVector; + } + + this.viewShadowMap.normalOffset = true; + this.viewShadowMap._terrainBias.depthBias = 0.0; + } + + /** + * Adds post processing to the SensorShadow. + * + * @private + */ + _addPostProcess() { + const SensorShadow = this; + + const viewShadowMap = this.viewShadowMap; + const primitiveBias = viewShadowMap._isPointLight + ? viewShadowMap._pointBias + : viewShadowMap._primitiveBias; + this.postProcess = this.viewer.scene.postProcessStages.add( + new PostProcessStage({ + fragmentShader: fsShader, + uniforms: { + view_distance: function () { + return SensorShadow.distance; + }, + viewArea_color: function () { + return SensorShadow.viewAreaColor; + }, + shadowArea_color: function () { + return SensorShadow.shadowAreaColor; + }, + percentShade: function () { + return SensorShadow.alpha; + }, + shadowMap: function () { + return viewShadowMap._shadowMapTexture; + }, + _shadowMap_cascadeSplits: function () { + return viewShadowMap._cascadeSplits; + }, + _shadowMap_cascadeMatrices: function () { + return viewShadowMap._cascadeMatrices; + }, + _shadowMap_cascadeDistances: function () { + return viewShadowMap._cascadeDistances; + }, + shadowMap_matrix: function () { + return viewShadowMap._shadowMapMatrix; + }, + shadowMap_camera_positionEC: function () { + return viewShadowMap._lightPositionEC; + }, + shadowMap_camera_directionEC: function () { + return viewShadowMap._lightDirectionEC; + }, + cameraPosition_WC: function () { + return SensorShadow.viewer.camera.positionWC; + }, + viewPosition_WC: function () { + return SensorShadow.viewPosition.getValue( + SensorShadow.viewer.clock.currentTime + ); + }, + shadowMap_camera_up: function () { + return viewShadowMap._lightCamera.up; + }, + shadowMap_camera_dir: function () { + return viewShadowMap._lightCamera.direction; + }, + shadowMap_camera_right: function () { + return viewShadowMap._lightCamera.right; + }, + ellipsoidInverseRadii: function () { + let radii = SensorShadow.viewer.scene.globe.ellipsoid.radii; + return new Cartesian3(1 / radii.x, 1 / radii.y, 1 / radii.z); + }, + shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: function () { + var viewShed2D = new Cartesian2(); + viewShed2D.x = 1 / viewShadowMap._textureSize.x; + viewShed2D.y = 1 / viewShadowMap._textureSize.y; + + return Cartesian4.fromElements( + viewShed2D.x, + viewShed2D.y, + this.depthBias, + primitiveBias.normalShadingSmooth, + this.combinedUniforms1 + ); + }, + shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: + function () { + return Cartesian4.fromElements( + primitiveBias.normalOffsetScale, + viewShadowMap._distance, + viewShadowMap.maximumDistance, + viewShadowMap._darkness, + this.combinedUniforms2 + ); + }, + exclude_terrain: function () { + return ( + SensorShadow.viewer.terrainProvider instanceof + EllipsoidTerrainProvider + ); + }, + }, + }) + ); + + // If a previous listener was added, remove it + if (this.preUpdateListener) { + viewer.scene.preUpdate.removeEventListener(this.preUpdateListener); + } + + // Add a new listener + this.preUpdateListener = () => { + if (!this.viewShadowMap._shadowMapTexture) { + this.postProcess.enabled = false; + } else { + this.postProcess.enabled = true; + } + }; + + viewer.scene.preUpdate.addEventListener(this.preUpdateListener); + } + + update(frameState) { + this._createShadowMap(true); + frameState.shadowMaps.push(this.viewShadowMap); + } + + destroy() { + if (this.preUpdateListener) { + viewer.scene.preUpdate.removeEventListener(this.preUpdateListener); + } + this.viewer.scene.postProcessStages.remove(this.postProcess); + for (let property in this) { + if (this.hasOwnProperty(property)) { + delete this[property]; + } + } + } + + get size() { + return this._size; + } + + set size(v) { + this._size = v; + } + + get depthBias() { + return this._depthBias; + } + + set depthBias(v) { + this._depthBias = v; + } + + get cameraPosition() { + return this._cameraPosition; + } + + set cameraPosition(v) { + this._cameraPosition = v; + } + + get viewPosition() { + return this._viewPosition; + } + + set viewPosition(v) { + this._viewPosition = v; + } + + get frustum() { + return this._frustum; + } + + set frustum(v) { + this._frustum = v; + } + + get distance() { + return this._distance; + } + + set distance(v) { + this._distance = v; + } + + get viewAreaColor() { + return this._viewAreaColor; + } + + set viewAreaColor(v) { + this._viewAreaColor = v; + } + + get shadowAreaColor() { + return this._shadowAreaColor; + } + + set shadowAreaColor(v) { + this._shadowAreaColor = v; + } + + get alpha() { + return this._alpha; + } + + set alpha(v) { + this._alpha = v; + } +} + +let pointA = Cesium.Cartesian3.fromDegrees(35.198213 ,33.264289, 250); // Central Park + +let pointB = Cesium.Cartesian3.fromDegrees( + 35.200014, 33.268811, 40 +); // Empire State Building + +const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() + }), + terrainProvider: new Cesium.CesiumTerrainProvider({ + url: new Cesium.Resource({ + url: DEM_URL, + queryParameters: { + token: TOKEN + } + }) + }), +}); + +viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ + url: new Cesium.Resource({ + url: MODEL_3D_URL, + queryParameters: { + token: TOKEN + } + }), + maximumScreenSpaceError: 5, + cullRequestsWhileMovingMultiplier: 120, + preloadFlightDestination: true, + preferLeaves: true, + skipLevelOfDetail: true +})); + + +viewer.camera.flyTo({ + destination: pointA, + orientation: { + heading: Cesium.Math.toRadians(25.0), + pitch: Cesium.Math.toRadians(-10.0), + roll: 0.0 + } +}); +viewer.camera.moveEnd.addEventListener(function () { + const { camera } = viewer; + if (camera.position?.clone) { + const cameraState = { + position: camera.position.clone(), + direction: camera.direction.clone(), + up: camera.up.clone() + }; + } +}); + +viewer.clock.shouldAnimate = false; +//return; +const redBall = viewer.entities.add({ + position: pointA, + point: { + pixelSize: 10, + color: Cesium.Color.RED, + }, +}); + +//return; +const blueBall = viewer.entities.add({ + position: pointB, + point: { + pixelSize: 10, + color: Cesium.Color.BLUE, + }, +}); + +//@ts-ignore +var sensorShadowInstance = new SensorShadow(viewer, { + cameraPosition: redBall.position, + viewPosition: pointB, +}); + + +let handler; +let pickedEntity; +let cartesian; +handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas); +handler.setInputAction((click) => { + cartesian = viewer.camera.pickEllipsoid(click.position, viewer.scene.globe.ellipsoid); + if (cartesian) { + var pickedObject = viewer.scene.pick(click.position); + if (Cesium.defined(pickedObject) && pickedObject.id === redBall) { + pickedEntity = pickedObject.id; + viewer.scene.screenSpaceCameraController.enableInputs = false; + } + } +}, Cesium.ScreenSpaceEventType.LEFT_DOWN); + +handler.setInputAction((movement) => { + if (pickedEntity) { + let newCartesian = viewer.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid); + if (newCartesian) { + // Convert the picked Cartesian3 to Cartographic + let newCartographic = Cesium.Cartographic.fromCartesian(newCartesian); + + // Get the original height + let originalCartographic = Cesium.Cartographic.fromCartesian( + pickedEntity.position.getValue(Cesium.JulianDate.now()) + ); + + // Update the height to the original one + newCartographic.height = originalCartographic.height; + + // Convert the updated Cartographic back to Cartesian3 + let updatedCartesian = Cesium.Cartographic.toCartesian(newCartographic); + + // Set the new position + pickedEntity.position = new Cesium.ConstantPositionProperty(updatedCartesian); + sensorShadowInstance.cameraPosition = pickedEntity.position; + } + } +}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); + +handler.setInputAction(() => { + if (pickedEntity) { + pickedEntity = undefined; + viewer.scene.screenSpaceCameraController.enableInputs = true; + } +}, Cesium.ScreenSpaceEventType.LEFT_UP); diff --git a/examples/cesium-wmts/cesium.html b/examples/cesium-wmts/cesium.html new file mode 100644 index 0000000..95872da --- /dev/null +++ b/examples/cesium-wmts/cesium.html @@ -0,0 +1 @@ +
diff --git a/examples/cesium-wmts/cesium.js b/examples/cesium-wmts/cesium.js new file mode 100644 index 0000000..e5f1354 --- /dev/null +++ b/examples/cesium-wmts/cesium.js @@ -0,0 +1,18 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; + +const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() + }), +}); diff --git a/examples/cesium.html b/examples/cesium.html new file mode 100644 index 0000000..95872da --- /dev/null +++ b/examples/cesium.html @@ -0,0 +1 @@ +
diff --git a/examples/cesium.js b/examples/cesium.js new file mode 100644 index 0000000..f663526 --- /dev/null +++ b/examples/cesium.js @@ -0,0 +1,16 @@ + +const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() + }), +}); diff --git a/examples/cesium_basic.js b/examples/cesium_basic.js new file mode 100644 index 0000000..31b2ea3 --- /dev/null +++ b/examples/cesium_basic.js @@ -0,0 +1,15 @@ +const viewer = new Cesium.Viewer('cesiumContainer', {}); + +const osm = new Cesium.OpenStreetMapImageryProvider({ + url: 'https://a.tile.openstreetmap.org/', +}); + +viewer.imageryLayers.addImageryProvider(osm); + +viewer.camera.flyTo({ + destination: Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 400), + orientation: { + heading: Cesium.Math.toRadians(0.0), + pitch: Cesium.Math.toRadians(-15.0), + }, +}); diff --git a/examples/cesium_wmts.js b/examples/cesium_wmts.js new file mode 100644 index 0000000..0e3f5cc --- /dev/null +++ b/examples/cesium_wmts.js @@ -0,0 +1,15 @@ +const viewer = new Cesium.Viewer('cesiumContainer', { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: RASTER_SERVICE_URL, + queryParameters: { + token: TOKEN + } + }), + layer: LAYER_NAME, + style: "default", + format: "image/jpeg", + tileMatrixSetID: "", + tilingScheme: new Cesium.GeographicTilingScheme() + }), +}); diff --git a/examples/config/3d-config.js b/examples/config/3d-config.js new file mode 100644 index 0000000..ee5acc1 --- /dev/null +++ b/examples/config/3d-config.js @@ -0,0 +1,3 @@ +import { MAPCOLONIES_TILES_URL } from './common-config.js'; + +export var MODEL_3D_URL = `${MAPCOLONIES_TILES_URL}/api/3d/v1/b3dm/d03ee59f-1676-4059-84cb-a0f68f15aefe/tileset.json`; diff --git a/examples/config/common-config.js b/examples/config/common-config.js new file mode 100644 index 0000000..638c52b --- /dev/null +++ b/examples/config/common-config.js @@ -0,0 +1,4 @@ +export var MAPCOLONIES_TILES_URL = 'https://tiles.mapcolonies.net'; +export var MAPCOLONIES_QUERY_URL = 'https://query.mapcolonies.net'; +export var MAPCOLONIES_GEOCODING_URL = 'https://geocoding.mapcolonies.net'; +export var TOKEN = 'eyJhbGciOiJSUzI1NiIsImtpZCI6Im1hcC1jb2xvbmllcy1pbnQifQ.eyJkIjpbInJhc3RlciIsInJhc3RlcldtcyIsInJhc3RlckV4cG9ydCIsImRlbSIsInZlY3RvciIsIjNkIl0sImlhdCI6MTY3NDYzMjM0Niwic3ViIjoibWFwY29sb25pZXMtYXBwIiwiaXNzIjoibWFwY29sb25pZXMtdG9rZW4tY2xpIn0.D1u28gFlxf_Z1bzIiRHZonUgrdWwhZy8DtmQj15cIzaABRUrGV2n_OJlgWTuNfrao0SbUZb_s0_qUUW6Gz_zO3ET2bVx5xQjBu0CaIWdmUPDjEYr6tw-eZx8EjFFIyq3rs-Fo0daVY9cX1B2aGW_GeJir1oMnJUURhABYRoh60azzl_utee9UdhDpnr_QElNtzJZIKogngsxCWp7tI7wkTuNCBaQM7aLEcymk0ktxlWEAt1E0nGt1R-bx-HnPeeQyZlxx4UQ1nuYTijpz7N8poaCCExOFeafj9T7megv2BzTrKWgfM1eai8srSgNa3I5wKuW0EyYnGZxdbJe8aseZg'; diff --git a/examples/config/dem-config.js b/examples/config/dem-config.js new file mode 100644 index 0000000..db90038 --- /dev/null +++ b/examples/config/dem-config.js @@ -0,0 +1,3 @@ +import { MAPCOLONIES_TILES_URL } from './common-config.js'; + +export var DEM_URL = `${MAPCOLONIES_TILES_URL}/api/dem/v1/terrains/srtm_100_30-aoi`; diff --git a/examples/config/raster-config.js b/examples/config/raster-config.js new file mode 100644 index 0000000..449a6bd --- /dev/null +++ b/examples/config/raster-config.js @@ -0,0 +1,8 @@ +import { MAPCOLONIES_TILES_URL, TOKEN } from './common-config.js'; + +var WMTS_BASE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/wmts`; + +export var LAYER_NAME = 'blueMarble-Orthophoto'; +export var RASTER_SERVICE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/service`; +export var WMTS_CAPABILITIES_URL = `${WMTS_BASE_URL}/1.0.0/WMTSCapabilities.xml?token=${TOKEN}`; +export var WMTS_URL = `${WMTS_BASE_URL}/${LAYER_NAME}/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.jpeg` diff --git a/examples/config/vector-config.js b/examples/config/vector-config.js new file mode 100644 index 0000000..c0a8a29 --- /dev/null +++ b/examples/config/vector-config.js @@ -0,0 +1,4 @@ +import { MAPCOLONIES_QUERY_URL, MAPCOLONIES_GEOCODING_URL } from './common-config.js'; + +export var VECTOR_WFS_URL = `${MAPCOLONIES_QUERY_URL}/api/vector/v1/core/wfs`; +export var GEOCODING_URL = `${MAPCOLONIES_GEOCODING_URL}/api/osm/v1/search`; diff --git a/examples/index.json b/examples/index.json new file mode 100644 index 0000000..b96fb94 --- /dev/null +++ b/examples/index.json @@ -0,0 +1,209 @@ +{ + "OpenLayers": { + "WMTS": { + "displayName": "WMTS", + "files": ["openlayers-wmts/wmts.js", "config/common-config.js", "config/raster-config.js", "openlayers-wmts/openlayers.css", "openlayers-wmts/openlayers.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "OverviewMap": { + "displayName": "OverviewMap(MiniMap)", + "files": ["openlayers-overview-map/overview-map.js", "config/common-config.js", "config/raster-config.js", "openlayers-overview-map/overview-map.css", "openlayers-overview-map/overview-map.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "Permalink": { + "displayName": "Permalink", + "files": ["openlayers-permalink/permalink.js", "config/common-config.js", "config/raster-config.js", "openlayers-permalink/permalink.css", "openlayers-permalink/permalink.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "QueryService": { + "displayName": "QueryService", + "files": ["openlayers-query-service/query-service.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-query-service/openlayers.css", "openlayers-query-service/openlayers.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "InteractiveFeatureSelect": { + "displayName": "Interactive Feature Select", + "files": ["openlayers-box-selection/box-selection.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-box-selection/openlayers.css", "openlayers-box-selection/box-selection.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "InteractiveSensitiveBuildings": { + "displayName": "Interactive Sensitive Buldings Select", + "files": ["openlayers-sensitive/interactive-sensitive.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-sensitive/openlayers.css", "openlayers-sensitive/openlayers.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "Debug Layer": { + "displayName": "DebugLayer", + "files": ["openlayers-debug-layer/debug-layer.js", "config/common-config.js", "config/raster-config.js", "openlayers-debug-layer/openlayers.css", "openlayers-debug-layer/openlayers.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "DrawAndModify": { + "displayName": "Draw and Modify Geodesic", + "files": ["openlayers-draw-and-modify/draw-and-modify.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-draw-and-modify/draw-and-modify.css", "openlayers-draw-and-modify/draw-and-modify.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "PreloadTiles": { + "displayName": "Preload Tiles", + "files": ["openlayers-preload/preload.js", "config/common-config.js", "config/raster-config.js", "openlayers-preload/preload.css", "openlayers-preload/preload.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "DrawStreetLabels": { + "displayName": "Draw Street Labels", + "files": ["openlayers-street-labels/street-labels.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-street-labels/street-labels.css", "openlayers-street-labels/street-labels.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "ol-ext": { + "displayName": "ol-ext", + "files": ["ol-ext-example/ol-ext.js", "config/common-config.js", "config/raster-config.js", "ol-ext-example/openlayers.css", "ol-ext-example/openlayers.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + + ] + } + }, + "cesium": { + "WMTS" : { + "displayName": "WMTS Imagery Provider", + "files": ["cesium-wmts/cesium.js", "config/common-config.js", "config/raster-config.js", "cesium-wmts/cesium.html"], + "links": [ + { + "name": "cesium.js", + "url": "/libs/Cesium/Cesium.js", + "type": "js" + }, + { + "name": "widgets.css", + "url": "/libs/Cesium/Widgets/widgets.css", + "type": "css" + } + ] + }, + "GeoCoding" : { + "displayName": "GeoCoding", + "files": ["cesium-geocoding/cesium.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "cesium-geocoding/cesium.html"], + "links": [ + { + "name": "cesium.js", + "url": "/libs/Cesium/Cesium.js", + "type": "js" + }, + { + "name": "widgets.css", + "url": "/libs/Cesium/Widgets/widgets.css", + "type": "css" + } + ] + }, + "Terrain" : { + "displayName": "Terrain Provider", + "files": ["cesium-terrain/cesium.js", "config/common-config.js", "config/raster-config.js", "config/dem-config.js", "cesium-terrain/cesium.html"], + "links": [ + { + "name": "cesium.js", + "url": "/libs/Cesium/Cesium.js", + "type": "js" + }, + { + "name": "widgets.css", + "url": "/libs/Cesium/Widgets/widgets.css", + "type": "css" + } + ] + }, + "3D Model": { + "displayName": "3D Model (South Lebanon)", + "files": ["cesium-3d/3d-model.js", "config/common-config.js", "config/raster-config.js", "config/3d-config.js", "cesium-3d/cesium.html"], + "links": [ + { + "name": "cesium.js", + "url": "/libs/Cesium/Cesium.js", + "type": "js" + }, + { + "name": "widgets.css", + "url": "/libs/Cesium/Widgets/widgets.css", + "type": "css" + } + ] + }, + "LayersSplit" : { + "displayName": "Layers Split", + "files": ["cesium-layers-split/split-layers.js", "config/common-config.js", "config/raster-config.js", "cesium-layers-split/split-layers.html", "cesium-layers-split/split-layers.css"], + "links": [ + { + "name": "cesium.js", + "url": "/libs/Cesium/Cesium.js", + "type": "js" + }, + { + "name": "widgets.css", + "url": "/libs/Cesium/Widgets/widgets.css", + "type": "css" + } + ] + }, + "ViewShed" : { + "displayName": "ViewShed", + "files": ["cesium-viewshed/viewshed.js", "config/common-config.js", "config/raster-config.js", "config/3d-config.js", "config/dem-config.js", "cesium-viewshed/viewshed.html", "cesium-viewshed/viewshed.css"], + "links": [ + { + "name": "cesium.js", + "url": "/libs/Cesium/Cesium.js", + "type": "js" + }, + { + "name": "widgets.css", + "url": "/libs/Cesium/Widgets/widgets.css", + "type": "css" + } + ] + } + }, + "leaflet": { + "WMTS": { + "displayName": "Basic WMTS Example", + "files": ["leaflet-wmts/wmts.js", "config/common-config.js", "config/raster-config.js", "leaflet-wmts/leaflet.css", "leaflet-wmts/leaflet.html"], + "links": [ + { + "name": "leaflet.js", + "url": "/libs/leaflet/1.9.4/leaflet.js", + "type": "js" + }, + { + "name": "leaflet.css", + "url": "/libs/leaflet/1.9.4/leaflet.css", + "type": "css" + } + ] + } + } +} diff --git a/examples/leaflet-wmts/leaflet.css b/examples/leaflet-wmts/leaflet.css new file mode 100644 index 0000000..79584dd --- /dev/null +++ b/examples/leaflet-wmts/leaflet.css @@ -0,0 +1,3 @@ +#map { + height: 100%; +} diff --git a/examples/leaflet-wmts/leaflet.html b/examples/leaflet-wmts/leaflet.html new file mode 100644 index 0000000..ad19e7d --- /dev/null +++ b/examples/leaflet-wmts/leaflet.html @@ -0,0 +1 @@ +
diff --git a/examples/leaflet-wmts/wmts.js b/examples/leaflet-wmts/wmts.js new file mode 100644 index 0000000..fb11034 --- /dev/null +++ b/examples/leaflet-wmts/wmts.js @@ -0,0 +1,15 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_URL } from './config/raster-config.js'; + +const parser = (urlTemplate) => { + return urlTemplate.replace("{TileMatrixSet}", "WorldCRS84").replace("{TileMatrix}", "{z}").replace("{TileRow}", "{y}").replace("{TileCol}", "{x}"); +} + +const urlTemplate = WMTS_URL; +const parsedUrl = parser(urlTemplate); + + +const map = L.map('map', { crs: L.CRS.EPSG4326 }).setView([0.0, 0.0], 1); +const layer = L.tileLayer(parsedUrl + `?token=${TOKEN}`, { id: LAYER_NAME }); + +map.addLayer(layer); diff --git a/examples/leaflet.css b/examples/leaflet.css new file mode 100644 index 0000000..79584dd --- /dev/null +++ b/examples/leaflet.css @@ -0,0 +1,3 @@ +#map { + height: 100%; +} diff --git a/examples/leaflet.html b/examples/leaflet.html new file mode 100644 index 0000000..ad19e7d --- /dev/null +++ b/examples/leaflet.html @@ -0,0 +1 @@ +
diff --git a/examples/leaflet_basic.js b/examples/leaflet_basic.js new file mode 100644 index 0000000..89f949b --- /dev/null +++ b/examples/leaflet_basic.js @@ -0,0 +1,7 @@ +const map = L.map('map').setView([51.505, -0.09], 13); + +L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: + '© OpenStreetMap', +}).addTo(map); diff --git a/examples/markdown.md b/examples/markdown.md new file mode 100644 index 0000000..8965c38 --- /dev/null +++ b/examples/markdown.md @@ -0,0 +1,30 @@ +# Heading level 1 +## Heading level 2 +### Heading level 3 + +Heading level 1 +=============== + +1. First item +2. Second item +3. Third item +4. Fourth item + +At the command prompt, type `nano`. + + + + +```javascript +function test() { + console.log("notice the blank line before this function?"); +} +``` + +```mermaid +graph TD; + A-->B; + A-->C; + B-->D; + C-->D; +``` \ No newline at end of file diff --git a/examples/ol-ext-example/ol-ext.js b/examples/ol-ext-example/ol-ext.js new file mode 100644 index 0000000..b9386c4 --- /dev/null +++ b/examples/ol-ext-example/ol-ext.js @@ -0,0 +1,27 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 0, + projection: 'EPSG:4326', + }), +}); + +const WMTSParser = new ol.format.WMTSCapabilities(); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + const layer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(layer); + }); diff --git a/examples/ol-ext-example/openlayers.css b/examples/ol-ext-example/openlayers.css new file mode 100644 index 0000000..dcac999 --- /dev/null +++ b/examples/ol-ext-example/openlayers.css @@ -0,0 +1,6 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/ol-ext-example/openlayers.html b/examples/ol-ext-example/openlayers.html new file mode 100644 index 0000000..ad19e7d --- /dev/null +++ b/examples/ol-ext-example/openlayers.html @@ -0,0 +1 @@ +
diff --git a/examples/openlayers-box-selection/box-selection.html b/examples/openlayers-box-selection/box-selection.html new file mode 100644 index 0000000..a03aaed --- /dev/null +++ b/examples/openlayers-box-selection/box-selection.html @@ -0,0 +1,13 @@ +
+
+
+

Using a DragBox interaction to select features.

+

This example shows how to use a DragBox interaction to select features. Selected features are added to the feature overlay of a select interaction (ol/interaction/Select) for highlighting.

Use Ctrl+Drag (Command+Drag on Mac) to draw boxes.

+
+
+ +
+

The selected Features are + +

+
\ No newline at end of file diff --git a/examples/openlayers-box-selection/box-selection.js b/examples/openlayers-box-selection/box-selection.js new file mode 100644 index 0000000..0d52ba7 --- /dev/null +++ b/examples/openlayers-box-selection/box-selection.js @@ -0,0 +1,157 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const WMTSParser = new ol.format.WMTSCapabilities(); + +const vectorSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 256})), + url: function(extent) { + return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json`; + } +}); + +const style = new ol.style.Style({ + fill: new ol.style.Fill({ + color: '#eeeeee' + }), +}); + +const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + constrainRotation: 16, + }), +}); + +const vectorLayer = new ol.layer.Vector({ + source: vectorSource, + style: function (feature) { + const color = feature.get('is_sensitive') === true ? 'red' : '#eeeeee'; + style.getFill().setColor(color); + return style; + }, + }) + + +const selectedStyle = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(180, 2, 180, 0.3)', + }), + stroke: new ol.style.Stroke({ + color: 'rgba(180, 2, 180, 0.4)', + width: 5, + }), +}); + +// a normal select interaction to handle click +const select = new ol.interaction.Select({ + style: function (feature) { + const color = feature.get('is_sensitive') === true ? 'red' : '#eeeeee'; + selectedStyle.getFill().setColor(color); + return selectedStyle; + }, +}); +map.addInteraction(select); + +const selectedFeatures = select.getFeatures(); + +// a DragBox interaction used to select features by drawing boxes +const dragBox = new ol.interaction.DragBox({ + condition: ol.events.condition.platformModifierKeyOnly, +}); + +map.addInteraction(dragBox); + +dragBox.on('boxend', function () { + const boxExtent = dragBox.getGeometry().getExtent(); + + // if the extent crosses the antimeridian process each world separately + const worldExtent = map.getView().getProjection().getExtent(); + const worldWidth = ol.extent.getWidth(worldExtent); + const startWorld = Math.floor((boxExtent[0] - worldExtent[0]) / worldWidth); + const endWorld = Math.floor((boxExtent[2] - worldExtent[0]) / worldWidth); + + for (let world = startWorld; world <= endWorld; ++world) { + const left = Math.max(boxExtent[0] - world * worldWidth, worldExtent[0]); + const right = Math.min(boxExtent[2] - world * worldWidth, worldExtent[2]); + const extent = [left, boxExtent[1], right, boxExtent[3]]; + + const boxFeatures = vectorSource + .getFeaturesInExtent(extent) + .filter( + (feature) => + !selectedFeatures.getArray().includes(feature) && + feature.getGeometry().intersectsExtent(extent) + ); + + // features that intersect the box geometry are added to the + // collection of selected features + + // if the view is not obliquely rotated the box geometry and + // its extent are equalivalent so intersecting features can + // be added directly to the collection + const rotation = map.getView().getRotation(); + const oblique = rotation % (Math.PI / 2) !== 0; + + // when the view is obliquely rotated the box extent will + // exceed its geometry so both the box and the candidate + // feature geometries are rotated around a common anchor + // to confirm that, with the box geometry aligned with its + // extent, the geometries intersect + if (oblique) { + const anchor = [0, 0]; + const geometry = dragBox.getGeometry().clone(); + geometry.translate(-world * worldWidth, 0); + geometry.rotate(-rotation, anchor); + const extent = geometry.getExtent(); + boxFeatures.forEach(function (feature) { + const geometry = feature.getGeometry().clone(); + geometry.rotate(-rotation, anchor); + if (geometry.intersectsExtent(extent)) { + selectedFeatures.push(feature); + } + }); + } else { + selectedFeatures.extend(boxFeatures); + } + } +}); + +// clear selection when drawing a new box and when clicking on the map +dragBox.on('boxstart', function () { + selectedFeatures.clear(); +}); + +const infoBox = document.getElementById('info'); + +selectedFeatures.on(['add', 'remove'], function () { + const names = selectedFeatures.getArray().map((feature) => { + return { 'סוג מבנה': feature.get('building_type'), GFID: feature.get('entity_id'), 'רגיש': feature.get('is_sensitive') }; + }); + console.clear(); + if (names.length > 0) { + infoBox.innerHTML = JSON.stringify(names, 2, 4); + } else { + infoBox.innerHTML = 'None'; + } +}); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + const rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(rasterLayer); + map.addLayer(vectorLayer); + +}); diff --git a/examples/openlayers-box-selection/openlayers.css b/examples/openlayers-box-selection/openlayers.css new file mode 100644 index 0000000..46a9541 --- /dev/null +++ b/examples/openlayers-box-selection/openlayers.css @@ -0,0 +1,6 @@ +#map { + top: 0; + bottom: 0; + height: 50%; + width: 100%; +} diff --git a/examples/openlayers-debug-layer/debug-layer.js b/examples/openlayers-debug-layer/debug-layer.js new file mode 100644 index 0000000..dc4e09f --- /dev/null +++ b/examples/openlayers-debug-layer/debug-layer.js @@ -0,0 +1,38 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 0, + projection: 'EPSG:4326', + }), +}); + +const WMTSParser = new ol.format.WMTSCapabilities(); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + const layer = new ol.layer.WebGLTile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(layer); + + const debugLayer = new ol.layer.WebGLTile({ + source: new ol.source.TileDebug({ + template: 'z:{z} x:{x}, y:{y}', + projection: layer.getSource().getProjection(), + tileGrid: layer.getSource().getTileGrid(), + zDirection: 1 + }) + }); + map.addLayer(debugLayer); + + }); diff --git a/examples/openlayers-debug-layer/openlayers.css b/examples/openlayers-debug-layer/openlayers.css new file mode 100644 index 0000000..dcac999 --- /dev/null +++ b/examples/openlayers-debug-layer/openlayers.css @@ -0,0 +1,6 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-debug-layer/openlayers.html b/examples/openlayers-debug-layer/openlayers.html new file mode 100644 index 0000000..ad19e7d --- /dev/null +++ b/examples/openlayers-debug-layer/openlayers.html @@ -0,0 +1 @@ +
diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.css b/examples/openlayers-draw-and-modify/draw-and-modify.css new file mode 100644 index 0000000..1e20f5c --- /dev/null +++ b/examples/openlayers-draw-and-modify/draw-and-modify.css @@ -0,0 +1,7 @@ +#map { + height: 70%; + top: 0; + bottom: 0; + width: 100%; +} + \ No newline at end of file diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.html b/examples/openlayers-draw-and-modify/draw-and-modify.html new file mode 100644 index 0000000..40c95db --- /dev/null +++ b/examples/openlayers-draw-and-modify/draw-and-modify.html @@ -0,0 +1,16 @@ +
+
+ + +
+ +
+

Example of using Draw and Modify interactions for geodesic circles.

+

Example of using the ol/interaction/Draw interaction with a custom geometry function together with the ol/interaction/Modify interaction to draw and modify geodesic circles (a ol/geom/Polygon#circular polygon representing a circle on the surface of the Earth's sphere). The polygon is placed in a ol/geom/GeometryCollection together with a ol/geom/Point which allows the Modify interaction to adjust the circle center as well as the radius. Custom style functions ensure the correct final geometry is displayed throughout. ol/geom/Circle projected (planar) geometries can also be drawn and modified. The difference between geodesic and projected circles can be seen when their centers are moved between northern and southern latitudes in the Web Mercator projection. The ol/interaction/Snap interaction can be used to create concentric circles.

+
\ No newline at end of file diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.js b/examples/openlayers-draw-and-modify/draw-and-modify.js new file mode 100644 index 0000000..6e1c683 --- /dev/null +++ b/examples/openlayers-draw-and-modify/draw-and-modify.js @@ -0,0 +1,192 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const map = new ol.Map({ + layers: [], + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 0, + projection: 'EPSG:4326', + }), +}); + +const WMTSParser = new ol.format.WMTSCapabilities(); + +const source = new ol.source.Vector(); + +const style = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)', + }), + stroke: new ol.style.Stroke({ + color: '#33cc33', + width: 2, + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: '#ffcc33', + }), + }), +}); + +const geodesicStyle = new ol.style.Style({ + geometry: function (feature) { + return feature.get('modifyGeometry') || feature.getGeometry(); + }, + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)', + }), + stroke: new ol.style.Stroke({ + color: '#ff3333', + width: 2, + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: 'rgba(0, 0, 0, 0)', + }), + }), +}); + +const vector = new ol.layer.Vector({ + source: source, + style: function (feature) { + const geometry = feature.getGeometry(); + return geometry.getType() === 'GeometryCollection' ? geodesicStyle : style; + }, +}); + + + +const defaultStyle = new ol.interaction.Modify({source: source}) + .getOverlay() + .getStyleFunction(); + +const modify = new ol.interaction.Modify({ + source: source, + style: function (feature) { + feature.get('features').forEach(function (modifyFeature) { + const modifyGeometry = modifyFeature.get('modifyGeometry'); + if (modifyGeometry) { + const modifyPoint = feature.getGeometry().getCoordinates(); + const geometries = modifyFeature.getGeometry().getGeometries(); + const polygon = geometries[0].getCoordinates()[0]; + const center = geometries[1].getCoordinates(); + const projection = map.getView().getProjection(); + let first, last, radius; + if (modifyPoint[0] === center[0] && modifyPoint[1] === center[1]) { + // center is being modified + // get unchanged radius from diameter between polygon vertices + first = ol.proj.transform(polygon[0], projection, 'EPSG:4326'); + last = ol.proj.transform( + polygon[(polygon.length - 1) / 2], + projection, + 'EPSG:4326' + ); + radius = ol.sphere.getDistance(first, last) / 2; + } else { + // radius is being modified + first = ol.proj.transform(center, projection, 'EPSG:4326'); + last = ol.proj.transform(modifyPoint, projection, 'EPSG:4326'); + radius = ol.sphere.getDistance(first, last); + } + // update the polygon using new center or radius + const circle = ol.geom.Circle( + ol.proj.transform(center, projection, 'EPSG:4326'), + radius, + 128 + ); + circle.transform('EPSG:4326', projection); + geometries[0].setCoordinates(circle.getCoordinates()); + // save changes to be applied at the end of the interaction + modifyGeometry.setGeometries(geometries); + } + }); + return defaultStyle(feature); + }, +}); + +modify.on('modifystart', function (event) { + event.features.forEach(function (feature) { + const geometry = feature.getGeometry(); + if (geometry.getType() === 'GeometryCollection') { + feature.set('modifyGeometry', geometry.clone(), true); + } + }); +}); + +modify.on('modifyend', function (event) { + event.features.forEach(function (feature) { + const modifyGeometry = feature.get('modifyGeometry'); + if (modifyGeometry) { + feature.setGeometry(modifyGeometry); + feature.unset('modifyGeometry', true); + } + }); +}); + +map.addInteraction(modify); + +let draw, snap; // global so we can remove them later +const typeSelect = document.getElementById('type'); + +function addInteractions() { + let value = typeSelect.value; + let geometryFunction; + if (value === 'Geodesic') { + value = 'Circle'; + geometryFunction = function (coordinates, geometry, projection) { + if (!geometry) { + geometry = new ol.geom.GeometryCollection([ + new ol.geom.Polygon([]), + new ol.geom.Point(coordinates[0]), + ]); + } + const geometries = geometry.getGeometries(); + const center = ol.proj.transform(coordinates[0], projection, 'EPSG:4326'); + const last = ol.proj.transform(coordinates[1], projection, 'EPSG:4326'); + const radius = ol.sphere.getDistance(center, last); + const circle = ol.geom.Polygon.circular(center, radius, 128); + circle.transform('EPSG:4326', projection); + geometries[0].setCoordinates(circle.getCoordinates()); + geometry.setGeometries(geometries); + return geometry; + }; + } + draw = new ol.interaction.Draw({ + source: source, + type: value, + geometryFunction: geometryFunction, + }); + map.addInteraction(draw); + snap = new ol.interaction.Snap({source: source}); + map.addInteraction(snap); +} + +/** + * Handle change event. + */ +typeSelect.onchange = function () { + map.removeInteraction(draw); + map.removeInteraction(snap); + addInteractions(); +}; + +addInteractions(); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + const layer = new ol.layer.WebGLTile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(layer); + map.addLayer(vector); + }); diff --git a/examples/openlayers-overview-map/overview-map.css b/examples/openlayers-overview-map/overview-map.css new file mode 100644 index 0000000..724d323 --- /dev/null +++ b/examples/openlayers-overview-map/overview-map.css @@ -0,0 +1,40 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} + + +.map .ol-custom-overviewmap, +.map .ol-custom-overviewmap.ol-uncollapsible { + bottom: auto; + left: auto; + right: 0; + top: 0; +} + +.map .ol-custom-overviewmap:not(.ol-collapsed) { + border: 1px solid black; +} + +.map .ol-custom-overviewmap .ol-overviewmap-map { + border: none; + width: 300px; +} + +.map .ol-custom-overviewmap .ol-overviewmap-box { + border: 2px solid red; +} + +.map .ol-custom-overviewmap:not(.ol-collapsed) button{ + bottom: auto; + left: auto; + right: 1px; + top: 1px; +} + +.map .ol-rotate { + top: 170px; + right: 0; +} diff --git a/examples/openlayers-overview-map/overview-map.html b/examples/openlayers-overview-map/overview-map.html new file mode 100644 index 0000000..2bc7f26 --- /dev/null +++ b/examples/openlayers-overview-map/overview-map.html @@ -0,0 +1 @@ +
diff --git a/examples/openlayers-overview-map/overview-map.js b/examples/openlayers-overview-map/overview-map.js new file mode 100644 index 0000000..910c98d --- /dev/null +++ b/examples/openlayers-overview-map/overview-map.js @@ -0,0 +1,38 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const WMTSParser = new ol.format.WMTSCapabilities(); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + const optionsMiniMap = ol.source.WMTS.optionsFromCapabilities(results, { + layer: 'OSM-RasterVectorBest' + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + optionsMiniMap.urls = optionsMiniMap.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options), preload: 10 }); + rasterLayer2 = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(optionsMiniMap) }); + const overviewMapControl = new ol.control.OverviewMap({layers: [rasterLayer2], collapsed: false}); + + const map = new ol.Map({ + controls: ol.control.defaults.defaults().extend([overviewMapControl]), + target: 'map', + layers: [rasterLayer], + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + minZoom: 1, + }), + }); + + }); diff --git a/examples/openlayers-permalink/permalink.css b/examples/openlayers-permalink/permalink.css new file mode 100644 index 0000000..1ff206f --- /dev/null +++ b/examples/openlayers-permalink/permalink.css @@ -0,0 +1,7 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} + \ No newline at end of file diff --git a/examples/openlayers-permalink/permalink.html b/examples/openlayers-permalink/permalink.html new file mode 100644 index 0000000..2fdafd8 --- /dev/null +++ b/examples/openlayers-permalink/permalink.html @@ -0,0 +1,3 @@ +
+ +
\ No newline at end of file diff --git a/examples/openlayers-permalink/permalink.js b/examples/openlayers-permalink/permalink.js new file mode 100644 index 0000000..beddf5a --- /dev/null +++ b/examples/openlayers-permalink/permalink.js @@ -0,0 +1,85 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +// default zoom, center and rotation +let zoom = 2; +let center = [0, 0]; +let rotation = 0; + +if (window.location.hash !== '') { + // try to restore center, zoom-level and rotation from the URL + const hash = window.location.hash.replace('#map=', ''); + const parts = hash.split('/'); + if (parts.length === 4) { + zoom = parseFloat(parts[0]); + center = [parseFloat(parts[1]), parseFloat(parts[2])]; + rotation = parseFloat(parts[3]); + } +} + +const WMTSParser = new ol.format.WMTSCapabilities(); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + const layer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: center, + zoom: zoom, + rotation: rotation, + projection: 'EPSG:4326', + }), + }); + map.addLayer(layer); + + let shouldUpdate = true; + const view = map.getView(); + const updatePermalink = function () { + if (!shouldUpdate) { + // do not update the URL when the view was changed in the 'popstate' handler + shouldUpdate = true; + return; + } + + const center = view.getCenter(); + const hash = + '#map=' + + view.getZoom().toFixed(2) + + '/' + + center[0].toFixed(2) + + '/' + + center[1].toFixed(2) + + '/' + + view.getRotation(); + const state = { + zoom: view.getZoom(), + center: view.getCenter(), + rotation: view.getRotation(), + }; + window.history.pushState(state, 'map', hash); + }; + + map.on('moveend', updatePermalink); + + // restore the view state when navigating through the history, see + // https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate + window.addEventListener('popstate', function (event) { + if (event.state === null) { + return; + } + map.getView().setCenter(event.state.center); + map.getView().setZoom(event.state.zoom); + map.getView().setRotation(event.state.rotation); + shouldUpdate = false; + }); + + }); diff --git a/examples/openlayers-preload/preload.css b/examples/openlayers-preload/preload.css new file mode 100644 index 0000000..7a61158 --- /dev/null +++ b/examples/openlayers-preload/preload.css @@ -0,0 +1,6 @@ +.map { + height: 50%; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-preload/preload.html b/examples/openlayers-preload/preload.html new file mode 100644 index 0000000..c76a9d8 --- /dev/null +++ b/examples/openlayers-preload/preload.html @@ -0,0 +1,2 @@ +
+
diff --git a/examples/openlayers-preload/preload.js b/examples/openlayers-preload/preload.js new file mode 100644 index 0000000..319c452 --- /dev/null +++ b/examples/openlayers-preload/preload.js @@ -0,0 +1,35 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const WMTSParser = new ol.format.WMTSCapabilities(); + +const sharedView = new ol.View({ + center: [0, 0], + zoom: 0, + projection: 'EPSG:4326', +}); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + const layerNoPreload = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + const layerPreload = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options), preload: 10 }); + + const mapPreload = new ol.Map({ + target: 'map-preload', + layers: [layerPreload], + view: sharedView, + }); + const mapNoPreload = new ol.Map({ + target: 'map-no-preload', + layers: [layerNoPreload], + view: sharedView, + }); + }); diff --git a/examples/openlayers-query-service/openlayers.css b/examples/openlayers-query-service/openlayers.css new file mode 100644 index 0000000..dcac999 --- /dev/null +++ b/examples/openlayers-query-service/openlayers.css @@ -0,0 +1,6 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-query-service/openlayers.html b/examples/openlayers-query-service/openlayers.html new file mode 100644 index 0000000..ad19e7d --- /dev/null +++ b/examples/openlayers-query-service/openlayers.html @@ -0,0 +1 @@ +
diff --git a/examples/openlayers-query-service/query-service.js b/examples/openlayers-query-service/query-service.js new file mode 100644 index 0000000..0ffeb64 --- /dev/null +++ b/examples/openlayers-query-service/query-service.js @@ -0,0 +1,53 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { VECTOR_WFS_URL } from './config/vector-config.js'; + +const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + }), +}); + +const WMTSParser = new ol.format.WMTSCapabilities(); +let rasterLayer; + + const vectorSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 512})), + url: function(extent) { + return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json&maxFeatures=10000`; + } + }); + + const vector = new ol.layer.Vector({ + source: vectorSource, + style: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'rgba(255,0,0,0.5)', + width: 3 + }), + fill: new ol.style.Fill({ color: 'rgba(255,50,0,0.5)' }) + }), + minZoom: 15, + maxZoom: 20 + }); + + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(rasterLayer); + map.addLayer(vector); + + }); diff --git a/examples/openlayers-sensitive/interactive-sensitive.js b/examples/openlayers-sensitive/interactive-sensitive.js new file mode 100644 index 0000000..a6db95b --- /dev/null +++ b/examples/openlayers-sensitive/interactive-sensitive.js @@ -0,0 +1,92 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { VECTOR_WFS_URL } from './config/vector-config.js'; + +const WMTSParser = new ol.format.WMTSCapabilities(); +let rasterLayer; + +const vectorSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 256})), + url: function(extent) { + return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json`; + } +}); + +const style = new ol.style.Style({ + fill: new ol.style.Fill({ + color: '#eeeeee' + }), +}); + +const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + constrainRotation: 16, + }), +}); + +const vectorLayer = new ol.layer.Vector({ + source: vectorSource, + style: function (feature) { + const color = feature.get('is_sensitive') === true ? 'rgba(255, 0, 0, 0.3)' : 'rgba(255, 255, 255, 0.7)'; + style.getFill().setColor(color); + return style; + }, + }) + + +const selectedStyle = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(180, 2, 180, 0.3)', + }), + stroke: new ol.style.Stroke({ + color: 'rgba(180, 2, 180, 0.4)', + width: 10, + }), +}); + +// a normal select interaction to handle click +const select = new ol.interaction.Select({ + style: function (feature) { + const color = feature.get('is_sensitive') === true ? 'rgba(255, 0, 0, 1)' : 'rgba(255, 255, 255, 1)'; + selectedStyle.getFill().setColor(color); + return selectedStyle; + }, +}); +map.addInteraction(select); + +const selectedFeatures = select.getFeatures(); + +const infoBox = document.getElementById('info'); + +selectedFeatures.on(['add', 'remove'], function () { + const names = selectedFeatures.getArray().map((feature) => { + return { 'סוג מבנה': feature.get('building_type'), GFID: feature.get('entity_id'), 'רגיש': feature.get('is_sensitive') }; + }); + console.clear(); + if (names.length > 0) { + infoBox.innerHTML = JSON.stringify(names, 2, 4); + } else { + infoBox.innerHTML = 'None'; + } +}); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(rasterLayer); + map.addLayer(vectorLayer); + +}); diff --git a/examples/openlayers-sensitive/openlayers.css b/examples/openlayers-sensitive/openlayers.css new file mode 100644 index 0000000..46a9541 --- /dev/null +++ b/examples/openlayers-sensitive/openlayers.css @@ -0,0 +1,6 @@ +#map { + top: 0; + bottom: 0; + height: 50%; + width: 100%; +} diff --git a/examples/openlayers-sensitive/openlayers.html b/examples/openlayers-sensitive/openlayers.html new file mode 100644 index 0000000..b6759df --- /dev/null +++ b/examples/openlayers-sensitive/openlayers.html @@ -0,0 +1,8 @@ +
+
+

Click on a sensitive feature (colored RED) to see details: + +

+
+
+ diff --git a/examples/openlayers-street-labels/street-labels.css b/examples/openlayers-street-labels/street-labels.css new file mode 100644 index 0000000..2af8466 --- /dev/null +++ b/examples/openlayers-street-labels/street-labels.css @@ -0,0 +1,7 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; + } + \ No newline at end of file diff --git a/examples/openlayers-street-labels/street-labels.html b/examples/openlayers-street-labels/street-labels.html new file mode 100644 index 0000000..b39cb78 --- /dev/null +++ b/examples/openlayers-street-labels/street-labels.html @@ -0,0 +1 @@ +
diff --git a/examples/openlayers-street-labels/street-labels.js b/examples/openlayers-street-labels/street-labels.js new file mode 100644 index 0000000..bd0dc4f --- /dev/null +++ b/examples/openlayers-street-labels/street-labels.js @@ -0,0 +1,70 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const WMTSParser = new ol.format.WMTSCapabilities(); +let rasterLayer; + + +const style = new ol.style.Style({ + text: new ol.style.Text({ + font: '20px "sans-serif"', + placement: 'line', + rotationWithView: true, + stroke: new ol.style.Stroke({ + color: 'white' + }), + fill: new ol.style.Fill({ + color: 'red', + }), + }), + stroke: new ol.style.Stroke({ + color: 'red' + }) +}); + +const vectorSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 256})), + url: function(extent) { + return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:roads_line&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json&count=10000`; + } + }); + +const vectorLayer = new ol.layer.Vector({ + declutter: true, + source: vectorSource, + style: function (feature) { + style.getText().setText(feature.get('name') === null ? 'לא ידוע' : feature.get('name')); + return style; + }, + minZoom: 15, + maxZoom: 20 + }); + +const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + minZoom: 12, + }), +}); + + + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(rasterLayer); + map.addLayer(vectorLayer); + + }); diff --git a/examples/openlayers-wmts/openlayers.css b/examples/openlayers-wmts/openlayers.css new file mode 100644 index 0000000..dcac999 --- /dev/null +++ b/examples/openlayers-wmts/openlayers.css @@ -0,0 +1,6 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-wmts/openlayers.html b/examples/openlayers-wmts/openlayers.html new file mode 100644 index 0000000..ad19e7d --- /dev/null +++ b/examples/openlayers-wmts/openlayers.html @@ -0,0 +1 @@ +
diff --git a/examples/openlayers-wmts/wmts.js b/examples/openlayers-wmts/wmts.js new file mode 100644 index 0000000..eee1023 --- /dev/null +++ b/examples/openlayers-wmts/wmts.js @@ -0,0 +1,27 @@ +import { TOKEN } from './config/common-config.js'; +import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; + +const WMTSParser = new ol.format.WMTSCapabilities(); + +const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 0, + projection: 'EPSG:4326', + }), +}); + +fetch(WMTS_CAPABILITIES_URL) + .then(response => response.text()) + .then(text => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: LAYER_NAME + }); + options.urls = options.urls.map(url => { + return url.concat(`?token=${TOKEN}`); + }); + const layer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(layer); + }); diff --git a/examples/openlayers.css b/examples/openlayers.css new file mode 100644 index 0000000..dcac999 --- /dev/null +++ b/examples/openlayers.css @@ -0,0 +1,6 @@ +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers.html b/examples/openlayers.html new file mode 100644 index 0000000..ad19e7d --- /dev/null +++ b/examples/openlayers.html @@ -0,0 +1 @@ +
diff --git a/examples/openlayers_basic.js b/examples/openlayers_basic.js new file mode 100644 index 0000000..79f6836 --- /dev/null +++ b/examples/openlayers_basic.js @@ -0,0 +1,5 @@ +const map = new ol.Map({ + target: 'map', + layers: [new ol.layer.Tile({ source: new ol.source.OSM() })], + view: new ol.View({ center: [0, 0], zoom: 2 }), +}); diff --git a/examples/openlayers_geojson.js b/examples/openlayers_geojson.js new file mode 100644 index 0000000..3cc723e --- /dev/null +++ b/examples/openlayers_geojson.js @@ -0,0 +1,241 @@ +const image = new ol.style.Circle({ + radius: 5, + fill: null, + stroke: new ol.style.Stroke({color: 'red', width: 1}), +}); + +const styles = { + 'Point': new ol.style.Style({ + image: image, + }), + 'LineString': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'green', + width: 1, + }), + }), + 'MultiLineString': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'green', + width: 1, + }), + }), + 'MultiPoint': new ol.style.Style({ + image: image, + }), + 'MultiPolygon': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'yellow', + width: 1, + }), + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 0, 0.1)', + }), + }), + 'Polygon': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'blue', + lineDash: [4], + width: 3, + }), + fill: new ol.style.Fill({ + color: 'rgba(0, 0, 255, 0.1)', + }), + }), + 'GeometryCollection': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'magenta', + width: 2, + }), + fill: new ol.style.Fill({ + color: 'magenta', + }), + image: new ol.style.Circle({ + radius: 10, + fill: null, + stroke: new ol.style.Stroke({ + color: 'magenta', + }), + }), + }), + 'Circle': new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'red', + width: 2, + }), + fill: new ol.style.Fill({ + color: 'rgba(255,0,0,0.2)', + }), + }), +}; + +const styleFunction = function (feature) { + return styles[feature.getGeometry().getType()]; +}; + +const geojsonObject = { + 'type': 'FeatureCollection', + 'crs': { + 'type': 'name', + 'properties': { + 'name': 'EPSG:3857', + }, + }, + 'features': [ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [0, 0], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [ + [4e6, -2e6], + [8e6, 2e6], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'LineString', + 'coordinates': [ + [4e6, 2e6], + [8e6, -2e6], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'Polygon', + 'coordinates': [ + [ + [-5e6, -1e6], + [-3e6, -1e6], + [-4e6, 1e6], + [-5e6, -1e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'MultiLineString', + 'coordinates': [ + [ + [-1e6, -7.5e5], + [-1e6, 7.5e5], + ], + [ + [1e6, -7.5e5], + [1e6, 7.5e5], + ], + [ + [-7.5e5, -1e6], + [7.5e5, -1e6], + ], + [ + [-7.5e5, 1e6], + [7.5e5, 1e6], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'MultiPolygon', + 'coordinates': [ + [ + [ + [-5e6, 6e6], + [-3e6, 6e6], + [-3e6, 8e6], + [-5e6, 8e6], + [-5e6, 6e6], + ], + ], + [ + [ + [-2e6, 6e6], + [0, 6e6], + [0, 8e6], + [-2e6, 8e6], + [-2e6, 6e6], + ], + ], + [ + [ + [1e6, 6e6], + [3e6, 6e6], + [3e6, 8e6], + [1e6, 8e6], + [1e6, 6e6], + ], + ], + ], + }, + }, + { + 'type': 'Feature', + 'geometry': { + 'type': 'GeometryCollection', + 'geometries': [ + { + 'type': 'LineString', + 'coordinates': [ + [-5e6, -5e6], + [0, -5e6], + ], + }, + { + 'type': 'Point', + 'coordinates': [4e6, -5e6], + }, + { + 'type': 'Polygon', + 'coordinates': [ + [ + [1e6, -6e6], + [3e6, -6e6], + [2e6, -4e6], + [1e6, -6e6], + ], + ], + }, + ], + }, + }, + ], +}; + +const vectorSource = new ol.source.Vector({ + features: new ol.format.GeoJSON().readFeatures(geojsonObject), +}); + +vectorSource.addFeature(new ol.Feature(new ol.geom.Circle([5e6, 7e6], 1e6))); + +const vectorLayer = new ol.layer.Vector({ + source: vectorSource, + style: styleFunction, +}); + +const map = new ol.Map({ + layers: [ + new ol.layer.Tile({ + source: new ol.source.OSM(), + }), + vectorLayer, + ], + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 2, + }), +}); diff --git a/package-lock.json b/package-lock.json index b7df295..f2d0932 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1590,6 +1590,261 @@ } } }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.17.19", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", @@ -1606,6 +1861,108 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -3508,6 +3865,21 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", diff --git a/package.json b/package.json index 1b48475..0f91f14 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --plugin-search-dir . --check . && eslint .", - "format": "prettier --plugin-search-dir . --write ." + "format": "prettier --plugin-search-dir . --write .", + "upload-examples": "bash scripts/upload-examples.sh" }, "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", diff --git a/scripts/upload-examples.sh b/scripts/upload-examples.sh new file mode 100755 index 0000000..2b9e47b --- /dev/null +++ b/scripts/upload-examples.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Upload all files under examples/ to S3. +# - New files are uploaded. +# - Existing files are uploaded only if their content differs (MD5 vs S3 ETag). +# - Identical files are skipped. +# Reads AWS_* env vars (same as the app). +# +# Usage: +# ./scripts/upload-examples.sh [examples-dir] +# +# The optional argument overrides the default examples/ directory. + +declare -A CMD_INSTALL=( + [aws]="AWS CLI v2 — https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html + Linux: curl 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' -o awscliv2.zip && unzip awscliv2.zip && sudo ./aws/install + macOS: brew install awscli + NOTE: avoid 'sudo apt install awscli' — the apt package (v1) conflicts with newer botocore" +) + +for cmd in "${!CMD_INSTALL[@]}"; do + if ! command -v "$cmd" &> /dev/null; then + echo "WARNING: '$cmd' is not installed or not in PATH." >&2 + echo " Install: ${CMD_INSTALL[$cmd]}" >&2 + exit 1 + fi +done + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + +# Load .env if present +if [[ -f "$REPO_ROOT/.env" ]]; then + set -a + # shellcheck disable=SC1091 + source "$REPO_ROOT/.env" + set +a +fi + +EXAMPLES_DIR="${1:-$REPO_ROOT/examples}" +BUCKET="${AWS_BUCKET:?AWS_BUCKET is required}" +ENDPOINT="${AWS_ENDPOINT_URL:-}" +REGION="${AWS_REGION:-us-east-1}" +PARALLELISM="${UPLOAD_PARALLELISM:-8}" + +if [[ ! -d "$EXAMPLES_DIR" ]]; then + echo "ERROR: examples directory not found: $EXAMPLES_DIR" >&2 + exit 1 +fi + +ENDPOINT_FLAG="" +if [[ -n "$ENDPOINT" ]]; then + ENDPOINT_FLAG="--endpoint-url $ENDPOINT" +fi + +# Fetch all existing S3 keys + ETags in one list-objects call. +# Output format per line: \t (ETag has surrounding quotes stripped) +echo "Fetching existing S3 objects..." +s3_index=$(mktemp) +trap 'rm -f "$s3_index"' EXIT + +aws s3api list-objects-v2 \ + --bucket "$BUCKET" \ + --region "$REGION" \ + $ENDPOINT_FLAG \ + --query 'Contents[].[Key, ETag]' \ + --output text 2>/dev/null \ + | sed 's/"//g' \ + | sort -k1,1 > "$s3_index" || true + +existing_count=$(wc -l < "$s3_index") +echo "Found $existing_count existing objects in S3." +echo "" + +# Temp dir for inter-process counters and upload list +tmp_dir=$(mktemp -d) +trap 'rm -f "$s3_index"; rm -rf "$tmp_dir"' EXIT +touch "$tmp_dir/uploaded" "$tmp_dir/updated" "$tmp_dir/skipped" "$tmp_dir/failed" +to_upload="$tmp_dir/to_upload" + +# Classify each local file in the main process. +# Subshells (xargs workers) only handle the actual aws s3 cp calls. +while IFS= read -r -d '' file; do + key="${file#$EXAMPLES_DIR/}" + local_md5=$(md5sum "$file" | cut -d' ' -f1) + + s3_entry=$(grep -P "^${key}\t" "$s3_index" || true) + + if [[ -z "$s3_entry" ]]; then + # New file + printf '%s\0' "new|$file" >> "$to_upload" + else + s3_etag=$(printf '%s' "$s3_entry" | awk '{print $2}') + if [[ "$local_md5" == "$s3_etag" ]]; then + echo "SKIP $key" + echo 1 >> "$tmp_dir/skipped" + else + # Changed file — overwrite + printf '%s\0' "update|$file" >> "$to_upload" + fi + fi +done < <(find "$EXAMPLES_DIR" -type f -print0 | sort -z) + +upload_file() { + local mode file key label + mode="${1%%|*}" + file="${1#*|}" + key="${file#$EXAMPLES_DIR/}" + label=$([ "$mode" = "update" ] && echo "UPDATE" || echo "UP") + + if aws s3 cp \ + "$file" \ + "s3://$BUCKET/$key" \ + --region "$REGION" \ + $ENDPOINT_FLAG \ + > /dev/null 2>&1; then + echo "$label $key" + echo 1 >> "$tmp_dir/$mode"d + else + echo "FAIL $key" >&2 + echo 1 >> "$tmp_dir/failed" + fi +} +export -f upload_file +export EXAMPLES_DIR BUCKET REGION ENDPOINT_FLAG tmp_dir + +if [[ -s "$to_upload" ]]; then + xargs -0 -P "$PARALLELISM" -I{} bash -c 'upload_file "$@"' _ {} < "$to_upload" +fi + +uploaded=$(wc -l < "$tmp_dir/uploaded") +updated=$(wc -l < "$tmp_dir/updated") +skipped=$(wc -l < "$tmp_dir/skipped") +failed=$(wc -l < "$tmp_dir/failed") + +echo "" +echo "Done — uploaded: $uploaded new, $updated updated, $skipped skipped, $failed failed" + +if ((failed > 0)); then + exit 1 +fi From 96d94c552b3572da5e509138909d5d8081b453e1 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 11 May 2026 09:52:20 +0300 Subject: [PATCH 02/21] chore: update config import path --- examples/config/3d-config.js | 2 +- examples/config/dem-config.js | 2 +- examples/config/raster-config.js | 2 +- examples/config/vector-config.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/config/3d-config.js b/examples/config/3d-config.js index ee5acc1..58fe6e9 100644 --- a/examples/config/3d-config.js +++ b/examples/config/3d-config.js @@ -1,3 +1,3 @@ -import { MAPCOLONIES_TILES_URL } from './common-config.js'; +import { MAPCOLONIES_TILES_URL } from './config/common-config.js'; export var MODEL_3D_URL = `${MAPCOLONIES_TILES_URL}/api/3d/v1/b3dm/d03ee59f-1676-4059-84cb-a0f68f15aefe/tileset.json`; diff --git a/examples/config/dem-config.js b/examples/config/dem-config.js index db90038..7dc55fb 100644 --- a/examples/config/dem-config.js +++ b/examples/config/dem-config.js @@ -1,3 +1,3 @@ -import { MAPCOLONIES_TILES_URL } from './common-config.js'; +import { MAPCOLONIES_TILES_URL } from './config/common-config.js'; export var DEM_URL = `${MAPCOLONIES_TILES_URL}/api/dem/v1/terrains/srtm_100_30-aoi`; diff --git a/examples/config/raster-config.js b/examples/config/raster-config.js index 449a6bd..d2c80e9 100644 --- a/examples/config/raster-config.js +++ b/examples/config/raster-config.js @@ -1,4 +1,4 @@ -import { MAPCOLONIES_TILES_URL, TOKEN } from './common-config.js'; +import { MAPCOLONIES_TILES_URL, TOKEN } from './config/common-config.js'; var WMTS_BASE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/wmts`; diff --git a/examples/config/vector-config.js b/examples/config/vector-config.js index c0a8a29..6ec23a7 100644 --- a/examples/config/vector-config.js +++ b/examples/config/vector-config.js @@ -1,4 +1,4 @@ -import { MAPCOLONIES_QUERY_URL, MAPCOLONIES_GEOCODING_URL } from './common-config.js'; +import { MAPCOLONIES_QUERY_URL, MAPCOLONIES_GEOCODING_URL } from './config/common-config.js'; export var VECTOR_WFS_URL = `${MAPCOLONIES_QUERY_URL}/api/vector/v1/core/wfs`; export var GEOCODING_URL = `${MAPCOLONIES_GEOCODING_URL}/api/osm/v1/search`; From 5e23827f0e3f5bd40d8a9617b535d0d5aa4252d8 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Mon, 11 May 2026 09:52:58 +0300 Subject: [PATCH 03/21] chore: allow uploading examples without assets --- package.json | 3 ++- scripts/upload-examples.sh | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 0f91f14..7bcce76 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --plugin-search-dir . --check . && eslint .", "format": "prettier --plugin-search-dir . --write .", - "upload-examples": "bash scripts/upload-examples.sh" + "upload-examples": "bash scripts/upload-examples.sh", + "upload-all": "bash scripts/upload-examples.sh --assets" }, "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", diff --git a/scripts/upload-examples.sh b/scripts/upload-examples.sh index 2b9e47b..e33a8c3 100755 --- a/scripts/upload-examples.sh +++ b/scripts/upload-examples.sh @@ -8,9 +8,11 @@ set -euo pipefail # Reads AWS_* env vars (same as the app). # # Usage: -# ./scripts/upload-examples.sh [examples-dir] +# ./scripts/upload-examples.sh [--assets|-a] [examples-dir] # -# The optional argument overrides the default examples/ directory. +# --assets / -a also upload the examples/assets/ folder (omit to skip it) +# +# The optional examples-dir argument overrides the default examples/ directory. declare -A CMD_INSTALL=( [aws]="AWS CLI v2 — https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html @@ -38,6 +40,15 @@ if [[ -f "$REPO_ROOT/.env" ]]; then set +a fi +INCLUDE_ASSETS=false +while [[ $# -gt 0 ]]; do + case "$1" in + -a|--assets) INCLUDE_ASSETS=true; shift ;; + -*) echo "ERROR: unknown option '$1'" >&2; exit 1 ;; + *) break ;; + esac +done + EXAMPLES_DIR="${1:-$REPO_ROOT/examples}" BUCKET="${AWS_BUCKET:?AWS_BUCKET is required}" ENDPOINT="${AWS_ENDPOINT_URL:-}" @@ -100,7 +111,13 @@ while IFS= read -r -d '' file; do printf '%s\0' "update|$file" >> "$to_upload" fi fi -done < <(find "$EXAMPLES_DIR" -type f -print0 | sort -z) +done < <( + if [[ "$INCLUDE_ASSETS" == "false" ]]; then + find "$EXAMPLES_DIR" -type f -not -path "$EXAMPLES_DIR/assets/*" -print0 + else + find "$EXAMPLES_DIR" -type f -print0 + fi | sort -z + ) upload_file() { local mode file key label From 863ef9332fce9ec704c16f2182fd56637ffc085d Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 24 May 2026 09:12:10 +0300 Subject: [PATCH 04/21] refactor: add layer image format constant --- examples/cesium-wmts/cesium.js | 4 ++-- examples/cesium.js | 4 +++- examples/cesium_wmts.js | 5 ++++- examples/config/raster-config.js | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/cesium-wmts/cesium.js b/examples/cesium-wmts/cesium.js index e5f1354..80d7e2d 100644 --- a/examples/cesium-wmts/cesium.js +++ b/examples/cesium-wmts/cesium.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; const viewer = new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ @@ -11,7 +11,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/cesium.js b/examples/cesium.js index f663526..80d7e2d 100644 --- a/examples/cesium.js +++ b/examples/cesium.js @@ -1,3 +1,5 @@ +import { TOKEN } from './config/common-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; const viewer = new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ @@ -9,7 +11,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/cesium_wmts.js b/examples/cesium_wmts.js index 0e3f5cc..033116d 100644 --- a/examples/cesium_wmts.js +++ b/examples/cesium_wmts.js @@ -1,3 +1,6 @@ +import { TOKEN } from './config/common-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; + const viewer = new Cesium.Viewer('cesiumContainer', { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ @@ -8,7 +11,7 @@ const viewer = new Cesium.Viewer('cesiumContainer', { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/config/raster-config.js b/examples/config/raster-config.js index d2c80e9..21e5b89 100644 --- a/examples/config/raster-config.js +++ b/examples/config/raster-config.js @@ -3,6 +3,7 @@ import { MAPCOLONIES_TILES_URL, TOKEN } from './config/common-config.js'; var WMTS_BASE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/wmts`; export var LAYER_NAME = 'blueMarble-Orthophoto'; +export var LAYER_IMAGE_FORMAT = 'image/png'; export var RASTER_SERVICE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/service`; export var WMTS_CAPABILITIES_URL = `${WMTS_BASE_URL}/1.0.0/WMTSCapabilities.xml?token=${TOKEN}`; export var WMTS_URL = `${WMTS_BASE_URL}/${LAYER_NAME}/{TileMatrixSet}/{TileMatrix}/{TileCol}/{TileRow}.jpeg` From c80457bc995b7a43b729359b14a0248709923072 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 26 May 2026 15:48:09 +0300 Subject: [PATCH 05/21] chore: update some examples --- examples/cesium-3d/3d-model.js | 4 ++-- examples/cesium-geocoding/cesium.js | 4 ++-- examples/cesium-layers-split/split-layers.js | 6 +++--- examples/cesium-terrain/cesium.js | 4 ++-- examples/cesium-viewshed/viewshed.js | 4 ++-- examples/config/raster-config.js | 1 + examples/index.json | 2 +- examples/openlayers-overview-map/overview-map.js | 8 ++++---- 8 files changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/cesium-3d/3d-model.js b/examples/cesium-3d/3d-model.js index d033004..411467f 100644 --- a/examples/cesium-3d/3d-model.js +++ b/examples/cesium-3d/3d-model.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; import { DEM_URL } from './config/dem-config.js'; import { MODEL_3D_URL } from './config/3d-config.js'; @@ -13,7 +13,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/cesium-geocoding/cesium.js b/examples/cesium-geocoding/cesium.js index bc11fba..abab7af 100644 --- a/examples/cesium-geocoding/cesium.js +++ b/examples/cesium-geocoding/cesium.js @@ -1,6 +1,6 @@ 'use strict'; import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; import { GEOCODING_URL } from './config/vector-config.js'; //Sandcastle_Begin @@ -63,7 +63,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/cesium-layers-split/split-layers.js b/examples/cesium-layers-split/split-layers.js index e12f390..06a2794 100644 --- a/examples/cesium-layers-split/split-layers.js +++ b/examples/cesium-layers-split/split-layers.js @@ -1,6 +1,6 @@ "use strict"; import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; const viewer = new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ @@ -12,7 +12,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", tilingScheme: new Cesium.GeographicTilingScheme() }), @@ -31,7 +31,7 @@ const secondLayer = layers.addImageryProvider( }), layer: "OSM-RasterVectorBest", style: "default", - format: "image/png", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/cesium-terrain/cesium.js b/examples/cesium-terrain/cesium.js index caf717a..4749ae2 100644 --- a/examples/cesium-terrain/cesium.js +++ b/examples/cesium-terrain/cesium.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; import { DEM_URL } from './config/dem-config.js'; const viewer = new Cesium.Viewer("cesiumContainer", { @@ -12,7 +12,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "newGrids", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/cesium-viewshed/viewshed.js b/examples/cesium-viewshed/viewshed.js index 8d46547..5598f30 100644 --- a/examples/cesium-viewshed/viewshed.js +++ b/examples/cesium-viewshed/viewshed.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, RASTER_SERVICE_URL } from './config/raster-config.js'; +import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; import { DEM_URL } from './config/dem-config.js'; import { MODEL_3D_URL } from './config/3d-config.js'; @@ -600,7 +600,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), layer: LAYER_NAME, style: "default", - format: "image/jpeg", + format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", tilingScheme: new Cesium.GeographicTilingScheme() }), diff --git a/examples/config/raster-config.js b/examples/config/raster-config.js index 21e5b89..14d7bda 100644 --- a/examples/config/raster-config.js +++ b/examples/config/raster-config.js @@ -3,6 +3,7 @@ import { MAPCOLONIES_TILES_URL, TOKEN } from './config/common-config.js'; var WMTS_BASE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/wmts`; export var LAYER_NAME = 'blueMarble-Orthophoto'; +export var ADDITIONAL_LAYER_NAME = 'blueMarble-Orthophoto'; export var LAYER_IMAGE_FORMAT = 'image/png'; export var RASTER_SERVICE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/service`; export var WMTS_CAPABILITIES_URL = `${WMTS_BASE_URL}/1.0.0/WMTSCapabilities.xml?token=${TOKEN}`; diff --git a/examples/index.json b/examples/index.json index b96fb94..0fe950c 100644 --- a/examples/index.json +++ b/examples/index.json @@ -141,7 +141,7 @@ }, "3D Model": { "displayName": "3D Model (South Lebanon)", - "files": ["cesium-3d/3d-model.js", "config/common-config.js", "config/raster-config.js", "config/3d-config.js", "cesium-3d/cesium.html"], + "files": ["cesium-3d/3d-model.js", "config/common-config.js", "config/raster-config.js", "config/3d-config.js", "config/dem-config.js", "cesium-3d/cesium.html"], "links": [ { "name": "cesium.js", diff --git a/examples/openlayers-overview-map/overview-map.js b/examples/openlayers-overview-map/overview-map.js index 910c98d..759d4a7 100644 --- a/examples/openlayers-overview-map/overview-map.js +++ b/examples/openlayers-overview-map/overview-map.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { WMTS_CAPABILITIES_URL, LAYER_NAME, ADDITIONAL_LAYER_NAME } from './config/raster-config.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -11,7 +11,7 @@ fetch(WMTS_CAPABILITIES_URL) layer: LAYER_NAME }); const optionsMiniMap = ol.source.WMTS.optionsFromCapabilities(results, { - layer: 'OSM-RasterVectorBest' + layer: ADDITIONAL_LAYER_NAME }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); @@ -19,8 +19,8 @@ fetch(WMTS_CAPABILITIES_URL) optionsMiniMap.urls = optionsMiniMap.urls.map(url => { return url.concat(`?token=${TOKEN}`); }); - rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options), preload: 10 }); - rasterLayer2 = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(optionsMiniMap) }); + let rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options), preload: 10 }); + let rasterLayer2 = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(optionsMiniMap) }); const overviewMapControl = new ol.control.OverviewMap({layers: [rasterLayer2], collapsed: false}); const map = new ol.Map({ From da077f52b26179587b725d8a23eb32f416bdfb92 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 4 Jun 2026 19:10:46 +0300 Subject: [PATCH 06/21] feat: replicate real mapcolonies flow --- examples/cesium-3d/3d-model.js | 93 ++++++------ examples/cesium-geocoding/cesium.js | 57 ++++---- examples/cesium-layers-split/split-layers.js | 134 +++++++++--------- examples/cesium-terrain/cesium.js | 95 +++++++------ examples/cesium-viewshed/viewshed.js | 25 ++-- examples/cesium-wmts/cesium.js | 31 ++-- examples/config/3d-config.js | 4 +- examples/config/common-config.js | 3 +- examples/config/dem-config.js | 4 +- examples/config/raster-config.js | 6 +- examples/index.json | 40 +++--- examples/leaflet-wmts/wmts.js | 15 +- examples/ol-ext-example/ol-ext.js | 8 +- .../openlayers-box-selection/box-selection.js | 8 +- .../openlayers-debug-layer/debug-layer.js | 8 +- .../draw-and-modify.js | 8 +- .../openlayers-overview-map/overview-map.js | 11 +- examples/openlayers-permalink/permalink.js | 8 +- examples/openlayers-preload/preload.js | 8 +- .../openlayers-query-service/query-service.js | 8 +- .../interactive-sensitive.js | 8 +- .../openlayers-street-labels/street-labels.js | 8 +- examples/openlayers-wmts/wmts.js | 8 +- examples/utils/catalog-client.js | 68 +++++++++ examples/utils/wmts-utils.js | 34 +++++ examples/utils/xml-utils.js | 8 ++ package-lock.json | 9 +- package.json | 10 +- 28 files changed, 447 insertions(+), 280 deletions(-) create mode 100644 examples/utils/catalog-client.js create mode 100644 examples/utils/wmts-utils.js create mode 100644 examples/utils/xml-utils.js diff --git a/examples/cesium-3d/3d-model.js b/examples/cesium-3d/3d-model.js index 411467f..dffefbb 100644 --- a/examples/cesium-3d/3d-model.js +++ b/examples/cesium-3d/3d-model.js @@ -1,52 +1,59 @@ import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; -import { DEM_URL } from './config/dem-config.js'; -import { MODEL_3D_URL } from './config/3d-config.js'; +import { PRODUCT_ID as RASTER_PRODUCT_ID, PRODUCT_TYPE as RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE } from './config/dem-config.js'; +import { PRODUCT_ID as MODEL_3D_PRODUCT_ID, PRODUCT_TYPE as MODEL_3D_PRODUCT_TYPE } from './config/3d-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; +import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; -const viewer = new Cesium.Viewer("cesiumContainer", { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } +Promise.all([ + fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), + fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, 'WCS'), + fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, '3DTiles'), +]).then(([tileTemplate, demUrl, modelUrl]) => { + const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: tileTemplate, + queryParameters: { + token: TOKEN + } + }), + layer: `${RASTER_PRODUCT_ID}-${RASTER_PRODUCT_TYPE}`, + style: "default", + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() }), - layer: LAYER_NAME, - style: "default", - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: "WorldCRS84", - tilingScheme: new Cesium.GeographicTilingScheme() - }), - terrainProvider: new Cesium.CesiumTerrainProvider({ - url: new Cesium.Resource({ - url: DEM_URL, - queryParameters: { - token: TOKEN - } - }) - }), -}); + terrainProvider: new Cesium.CesiumTerrainProvider({ + url: new Cesium.Resource({ + url: demUrl, + queryParameters: { + token: TOKEN + } + }) + }), + }); -viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ - url: new Cesium.Resource({ - url: MODEL_3D_URL, + viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ + url: new Cesium.Resource({ + url: modelUrl, queryParameters: { token: TOKEN } - }), - maximumScreenSpaceError: 5, - cullRequestsWhileMovingMultiplier: 120, - preloadFlightDestination: true, - preferLeaves: true, - skipLevelOfDetail: true -})); - + }), + maximumScreenSpaceError: 5, + cullRequestsWhileMovingMultiplier: 120, + preloadFlightDestination: true, + preferLeaves: true, + skipLevelOfDetail: true + })); -viewer.camera.flyTo({ - destination: Cesium.Cartesian3.fromDegrees(35.201436, 33.265378, 300), - orientation: { - heading: Cesium.Math.toRadians(25.0), - pitch: Cesium.Math.toRadians(-10.0), - roll: 0.0 - } + viewer.camera.flyTo({ + destination: Cesium.Cartesian3.fromDegrees(35.201436, 33.265378, 300), + orientation: { + heading: Cesium.Math.toRadians(25.0), + pitch: Cesium.Math.toRadians(-10.0), + roll: 0.0 + } + }); }); diff --git a/examples/cesium-geocoding/cesium.js b/examples/cesium-geocoding/cesium.js index abab7af..ce1293d 100644 --- a/examples/cesium-geocoding/cesium.js +++ b/examples/cesium-geocoding/cesium.js @@ -1,22 +1,11 @@ 'use strict'; import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; import { GEOCODING_URL } from './config/vector-config.js'; +import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; -//Sandcastle_Begin -/** - * This class is an example of a custom geocoder. It provides geocoding through the OpenStreetMap Nominatim service. - * @alias OpenStreetMapNominatimGeocoder - * @constructor - */ function OpenStreetMapNominatimGeocoder() {} -/** - * The function called to geocode using this geocoder service. - * - * @param {String} input The query to be sent to the geocoder service - * @returns {Promise} - */ OpenStreetMapNominatimGeocoder.prototype.geocode = function (input) { const resource = new Cesium.Resource({ url: GEOCODING_URL, @@ -47,25 +36,27 @@ OpenStreetMapNominatimGeocoder.prototype.geocode = function (input) { }); }; -const viewer = new Cesium.Viewer("cesiumContainer", { - vrButton: false, - homeButton: false, - infoBox: false, - timeline: false, - navigationHelpButton: false, - shouldAnimate: false, - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } +fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then(tileTemplate => { + new Cesium.Viewer("cesiumContainer", { + vrButton: false, + homeButton: false, + infoBox: false, + timeline: false, + navigationHelpButton: false, + shouldAnimate: false, + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: tileTemplate, + queryParameters: { + token: TOKEN + } + }), + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, + style: "default", + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() }), - layer: LAYER_NAME, - style: "default", - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: "WorldCRS84", - tilingScheme: new Cesium.GeographicTilingScheme() - }), - geocoder: new OpenStreetMapNominatimGeocoder(), + geocoder: new OpenStreetMapNominatimGeocoder(), + }); }); diff --git a/examples/cesium-layers-split/split-layers.js b/examples/cesium-layers-split/split-layers.js index 06a2794..3056269 100644 --- a/examples/cesium-layers-split/split-layers.js +++ b/examples/cesium-layers-split/split-layers.js @@ -1,78 +1,84 @@ "use strict"; import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; -const viewer = new Cesium.Viewer("cesiumContainer", { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } +Promise.all([ + fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT), + fetchWmtsTileTemplate('OSM', 'RasterVectorBest', LAYER_IMAGE_FORMAT), +]).then(([mainTemplate, secondTemplate]) => { + const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: mainTemplate, + queryParameters: { + token: TOKEN + } + }), + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, + style: "default", + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() }), - layer: LAYER_NAME, - style: "default", - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: "WorldCRS84", - tilingScheme: new Cesium.GeographicTilingScheme() - }), - baseLayerPicker: false, - infoBox: false, -}); + baseLayerPicker: false, + infoBox: false, + }); -const layers = viewer.imageryLayers; -const secondLayer = layers.addImageryProvider( - new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } + const layers = viewer.imageryLayers; + const secondLayer = layers.addImageryProvider( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: secondTemplate, + queryParameters: { + token: TOKEN + } + }), + layer: "OSM-RasterVectorBest", + style: "default", + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() }), - layer: "OSM-RasterVectorBest", - style: "default", - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: "WorldCRS84", - tilingScheme: new Cesium.GeographicTilingScheme() - }), -); -secondLayer.splitDirection = Cesium.SplitDirection.LEFT; // Only show to the left of the slider. + ); + secondLayer.splitDirection = Cesium.SplitDirection.LEFT; // Only show to the left of the slider. -// Sync the position of the slider with the split position -const slider = document.getElementById("slider"); -viewer.scene.splitPosition = - slider.offsetLeft / slider.parentElement.offsetWidth; + // Sync the position of the slider with the split position + const slider = document.getElementById("slider"); + viewer.scene.splitPosition = + slider.offsetLeft / slider.parentElement.offsetWidth; -const handler = new Cesium.ScreenSpaceEventHandler(slider); + const handler = new Cesium.ScreenSpaceEventHandler(slider); -let moveActive = false; + let moveActive = false; -function move(movement) { - if (!moveActive) { - return; - } + function move(movement) { + if (!moveActive) { + return; + } - const relativeOffset = movement.endPosition.x; - const splitPosition = - (slider.offsetLeft + relativeOffset) / - slider.parentElement.offsetWidth; - slider.style.left = `${100.0 * splitPosition}%`; - viewer.scene.splitPosition = splitPosition; -} + const relativeOffset = movement.endPosition.x; + const splitPosition = + (slider.offsetLeft + relativeOffset) / + slider.parentElement.offsetWidth; + slider.style.left = `${100.0 * splitPosition}%`; + viewer.scene.splitPosition = splitPosition; + } -handler.setInputAction(function () { - moveActive = true; -}, Cesium.ScreenSpaceEventType.LEFT_DOWN); -handler.setInputAction(function () { - moveActive = true; -}, Cesium.ScreenSpaceEventType.PINCH_START); + handler.setInputAction(function () { + moveActive = true; + }, Cesium.ScreenSpaceEventType.LEFT_DOWN); + handler.setInputAction(function () { + moveActive = true; + }, Cesium.ScreenSpaceEventType.PINCH_START); -handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE); -handler.setInputAction(move, Cesium.ScreenSpaceEventType.PINCH_MOVE); + handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE); + handler.setInputAction(move, Cesium.ScreenSpaceEventType.PINCH_MOVE); -handler.setInputAction(function () { - moveActive = false; -}, Cesium.ScreenSpaceEventType.LEFT_UP); -handler.setInputAction(function () { - moveActive = false; -}, Cesium.ScreenSpaceEventType.PINCH_END); + handler.setInputAction(function () { + moveActive = false; + }, Cesium.ScreenSpaceEventType.LEFT_UP); + handler.setInputAction(function () { + moveActive = false; + }, Cesium.ScreenSpaceEventType.PINCH_END); +}); diff --git a/examples/cesium-terrain/cesium.js b/examples/cesium-terrain/cesium.js index 4749ae2..b303d62 100644 --- a/examples/cesium-terrain/cesium.js +++ b/examples/cesium-terrain/cesium.js @@ -1,50 +1,59 @@ import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; -import { DEM_URL } from './config/dem-config.js'; +import { PRODUCT_ID as RASTER_PRODUCT_ID, PRODUCT_TYPE as RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE } from './config/dem-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; +import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; -const viewer = new Cesium.Viewer("cesiumContainer", { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } +Promise.all([ + fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), + fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, 'WCS'), +]).then(([tileTemplate, demUrl]) => { + const viewer = new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: tileTemplate, + queryParameters: { + token: TOKEN + } + }), + layer: `${RASTER_PRODUCT_ID}-${RASTER_PRODUCT_TYPE}`, + style: "default", + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: "newGrids", + tilingScheme: new Cesium.GeographicTilingScheme() }), - layer: LAYER_NAME, - style: "default", - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: "newGrids", - tilingScheme: new Cesium.GeographicTilingScheme() - }), terrainProvider: new Cesium.CesiumTerrainProvider({ - url: new Cesium.Resource({ - url: DEM_URL, - queryParameters: { - token: TOKEN - } + url: new Cesium.Resource({ + url: demUrl, + queryParameters: { + token: TOKEN + } + }) }) - }) -}); + }); -viewer.camera.flyTo({ - destination: Cesium.Cartesian3.fromDegrees(35.567306, 33.210784, 6000), - orientation: { - heading: Cesium.Math.toRadians(25.0), - pitch: Cesium.Math.toRadians(-10.0), - roll: 0.0 - } -}); + viewer.camera.flyTo({ + destination: Cesium.Cartesian3.fromDegrees(35.567306, 33.210784, 6000), + orientation: { + heading: Cesium.Math.toRadians(25.0), + pitch: Cesium.Math.toRadians(-10.0), + roll: 0.0 + } + }); -viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } - }), - layer: "WORLD_MAP_BASE_THIN-RasterVectorBest", - style: "default", - format: "image/png", - tileMatrixSetID: "newGrids", - tilingScheme: new Cesium.GeographicTilingScheme() - })); + fetchWmtsTileTemplate('WORLD_MAP_BASE_THIN', 'RasterVectorBest', 'image/png').then(secondTemplate => { + viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: secondTemplate, + queryParameters: { + token: TOKEN + } + }), + layer: "WORLD_MAP_BASE_THIN-RasterVectorBest", + style: "default", + format: "image/png", + tileMatrixSetID: "newGrids", + tilingScheme: new Cesium.GeographicTilingScheme() + })); + }); +}); diff --git a/examples/cesium-viewshed/viewshed.js b/examples/cesium-viewshed/viewshed.js index 5598f30..a422541 100644 --- a/examples/cesium-viewshed/viewshed.js +++ b/examples/cesium-viewshed/viewshed.js @@ -1,7 +1,9 @@ import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; -import { DEM_URL } from './config/dem-config.js'; -import { MODEL_3D_URL } from './config/3d-config.js'; +import { PRODUCT_ID as RASTER_PRODUCT_ID, PRODUCT_TYPE as RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE } from './config/dem-config.js'; +import { PRODUCT_ID as MODEL_3D_PRODUCT_ID, PRODUCT_TYPE as MODEL_3D_PRODUCT_TYPE } from './config/3d-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; +import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; const fsShaderText = ` #define USE_NORMAL_SHADING @@ -590,15 +592,21 @@ let pointB = Cesium.Cartesian3.fromDegrees( 35.200014, 33.268811, 40 ); // Empire State Building -const viewer = new Cesium.Viewer("cesiumContainer", { +let viewer; +Promise.all([ + fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), + fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, 'WCS'), + fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, '3DTiles'), +]).then(([tileTemplate, demUrl, modelUrl]) => { +viewer = new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, + url: tileTemplate, queryParameters: { token: TOKEN } }), - layer: LAYER_NAME, + layer: `${RASTER_PRODUCT_ID}-${RASTER_PRODUCT_TYPE}`, style: "default", format: LAYER_IMAGE_FORMAT, tileMatrixSetID: "WorldCRS84", @@ -606,7 +614,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { }), terrainProvider: new Cesium.CesiumTerrainProvider({ url: new Cesium.Resource({ - url: DEM_URL, + url: demUrl, queryParameters: { token: TOKEN } @@ -616,7 +624,7 @@ const viewer = new Cesium.Viewer("cesiumContainer", { viewer.scene.primitives.add(new Cesium.Cesium3DTileset({ url: new Cesium.Resource({ - url: MODEL_3D_URL, + url: modelUrl, queryParameters: { token: TOKEN } @@ -720,3 +728,4 @@ handler.setInputAction(() => { viewer.scene.screenSpaceCameraController.enableInputs = true; } }, Cesium.ScreenSpaceEventType.LEFT_UP); +}); diff --git a/examples/cesium-wmts/cesium.js b/examples/cesium-wmts/cesium.js index 80d7e2d..5b01d57 100644 --- a/examples/cesium-wmts/cesium.js +++ b/examples/cesium-wmts/cesium.js @@ -1,18 +1,21 @@ import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; +import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; -const viewer = new Cesium.Viewer("cesiumContainer", { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } +fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then(tileTemplate => { + new Cesium.Viewer("cesiumContainer", { + imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: tileTemplate, + queryParameters: { + token: TOKEN + } + }), + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, + style: "default", + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: "WorldCRS84", + tilingScheme: new Cesium.GeographicTilingScheme() }), - layer: LAYER_NAME, - style: "default", - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: "WorldCRS84", - tilingScheme: new Cesium.GeographicTilingScheme() - }), + }); }); diff --git a/examples/config/3d-config.js b/examples/config/3d-config.js index 58fe6e9..7e9382c 100644 --- a/examples/config/3d-config.js +++ b/examples/config/3d-config.js @@ -1,3 +1,5 @@ import { MAPCOLONIES_TILES_URL } from './config/common-config.js'; -export var MODEL_3D_URL = `${MAPCOLONIES_TILES_URL}/api/3d/v1/b3dm/d03ee59f-1676-4059-84cb-a0f68f15aefe/tileset.json`; +export var PRODUCT_ID = 'd03ee59f-1676-4059-84cb-a0f68f15aefe'; +export var PRODUCT_TYPE = '3DPhotoRealistic'; +export var MODEL_3D_URL = `${MAPCOLONIES_TILES_URL}/api/3d/v1/b3dm/${PRODUCT_ID}/tileset.json`; diff --git a/examples/config/common-config.js b/examples/config/common-config.js index 638c52b..f201ed1 100644 --- a/examples/config/common-config.js +++ b/examples/config/common-config.js @@ -1,4 +1,5 @@ export var MAPCOLONIES_TILES_URL = 'https://tiles.mapcolonies.net'; export var MAPCOLONIES_QUERY_URL = 'https://query.mapcolonies.net'; export var MAPCOLONIES_GEOCODING_URL = 'https://geocoding.mapcolonies.net'; -export var TOKEN = 'eyJhbGciOiJSUzI1NiIsImtpZCI6Im1hcC1jb2xvbmllcy1pbnQifQ.eyJkIjpbInJhc3RlciIsInJhc3RlcldtcyIsInJhc3RlckV4cG9ydCIsImRlbSIsInZlY3RvciIsIjNkIl0sImlhdCI6MTY3NDYzMjM0Niwic3ViIjoibWFwY29sb25pZXMtYXBwIiwiaXNzIjoibWFwY29sb25pZXMtdG9rZW4tY2xpIn0.D1u28gFlxf_Z1bzIiRHZonUgrdWwhZy8DtmQj15cIzaABRUrGV2n_OJlgWTuNfrao0SbUZb_s0_qUUW6Gz_zO3ET2bVx5xQjBu0CaIWdmUPDjEYr6tw-eZx8EjFFIyq3rs-Fo0daVY9cX1B2aGW_GeJir1oMnJUURhABYRoh60azzl_utee9UdhDpnr_QElNtzJZIKogngsxCWp7tI7wkTuNCBaQM7aLEcymk0ktxlWEAt1E0nGt1R-bx-HnPeeQyZlxx4UQ1nuYTijpz7N8poaCCExOFeafj9T7megv2BzTrKWgfM1eai8srSgNa3I5wKuW0EyYnGZxdbJe8aseZg'; +export var MAPCOLONIES_CATALOG_URL = 'https://catalog.mapcolonies.net'; +export var TOKEN = 'eyJhbGciOiJSUzI1NiIsImtpZCI6Im1hcC1jb2xvbmllcy1pbnQifQ.eyJkIjpbInJhc3RlciIsInZlY3RvciIsIjNkIiwiZGVtIl0sImlhdCI6MTcxMTU2MDY0NSwic3ViIjoiYmFyYWsiLCJpc3MiOiJtYXBjb2xvbmllcy10b2tlbi1jbGkifQ.qupSnHv9H1N9A9iKS5CCNO7A6LKipR3TpFYz_ViV2iqKWIIv3pUlQ_SFESubZiL-TuRFBaxzC8HqUmzV1Q0F3M209QzSOhPyzGme-oFQncqfJstKm_ji8Q6weR9RkZVzfssRed1C6FY1D4bHH-q8qLBKnorU_S0aYbHMwawHLTAmKoDBPetADLT64doxLy5kCpgL0dPQLdXQKIlLqw1whXsk_x4UG1BYtD-Zb0lxJ_FkaZWWfU5cpgFgDQo7gI2q0oUlxZPqCmpiKhq3njWZWmDv-G8S8XcNNeml94dVjHnqFbc_DKxHLXV2QuIS3koPUTHdyctaHtxaCEKW0XHOfA'; diff --git a/examples/config/dem-config.js b/examples/config/dem-config.js index 7dc55fb..36d144c 100644 --- a/examples/config/dem-config.js +++ b/examples/config/dem-config.js @@ -1,3 +1,5 @@ import { MAPCOLONIES_TILES_URL } from './config/common-config.js'; -export var DEM_URL = `${MAPCOLONIES_TILES_URL}/api/dem/v1/terrains/srtm_100_30-aoi`; +export var PRODUCT_ID = 'srtm_100_30-aoi'; +export var PRODUCT_TYPE = 'DTM'; +export var DEM_URL = `${MAPCOLONIES_TILES_URL}/api/dem/v1/terrains/${PRODUCT_ID}`; diff --git a/examples/config/raster-config.js b/examples/config/raster-config.js index 14d7bda..f07df1f 100644 --- a/examples/config/raster-config.js +++ b/examples/config/raster-config.js @@ -2,8 +2,10 @@ import { MAPCOLONIES_TILES_URL, TOKEN } from './config/common-config.js'; var WMTS_BASE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/wmts`; -export var LAYER_NAME = 'blueMarble-Orthophoto'; -export var ADDITIONAL_LAYER_NAME = 'blueMarble-Orthophoto'; +export var PRODUCT_ID = 'blueMarble'; +export var PRODUCT_TYPE = 'Orthophoto'; +export var LAYER_NAME = `${PRODUCT_ID}-${PRODUCT_TYPE}`; +export var ADDITIONAL_LAYER_NAME = `${PRODUCT_ID}-${PRODUCT_TYPE}` export var LAYER_IMAGE_FORMAT = 'image/png'; export var RASTER_SERVICE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/service`; export var WMTS_CAPABILITIES_URL = `${WMTS_BASE_URL}/1.0.0/WMTSCapabilities.xml?token=${TOKEN}`; diff --git a/examples/index.json b/examples/index.json index 0fe950c..ba0175a 100644 --- a/examples/index.json +++ b/examples/index.json @@ -2,7 +2,7 @@ "OpenLayers": { "WMTS": { "displayName": "WMTS", - "files": ["openlayers-wmts/wmts.js", "config/common-config.js", "config/raster-config.js", "openlayers-wmts/openlayers.css", "openlayers-wmts/openlayers.html"], + "files": ["openlayers-wmts/wmts.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "openlayers-wmts/openlayers.css", "openlayers-wmts/openlayers.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -10,7 +10,7 @@ }, "OverviewMap": { "displayName": "OverviewMap(MiniMap)", - "files": ["openlayers-overview-map/overview-map.js", "config/common-config.js", "config/raster-config.js", "openlayers-overview-map/overview-map.css", "openlayers-overview-map/overview-map.html"], + "files": ["openlayers-overview-map/overview-map.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "openlayers-overview-map/overview-map.css", "openlayers-overview-map/overview-map.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -18,7 +18,7 @@ }, "Permalink": { "displayName": "Permalink", - "files": ["openlayers-permalink/permalink.js", "config/common-config.js", "config/raster-config.js", "openlayers-permalink/permalink.css", "openlayers-permalink/permalink.html"], + "files": ["openlayers-permalink/permalink.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "openlayers-permalink/permalink.css", "openlayers-permalink/permalink.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -26,7 +26,7 @@ }, "QueryService": { "displayName": "QueryService", - "files": ["openlayers-query-service/query-service.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-query-service/openlayers.css", "openlayers-query-service/openlayers.html"], + "files": ["openlayers-query-service/query-service.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "config/vector-config.js", "openlayers-query-service/openlayers.css", "openlayers-query-service/openlayers.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -34,7 +34,7 @@ }, "InteractiveFeatureSelect": { "displayName": "Interactive Feature Select", - "files": ["openlayers-box-selection/box-selection.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-box-selection/openlayers.css", "openlayers-box-selection/box-selection.html"], + "files": ["openlayers-box-selection/box-selection.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "config/vector-config.js", "openlayers-box-selection/openlayers.css", "openlayers-box-selection/box-selection.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -42,7 +42,7 @@ }, "InteractiveSensitiveBuildings": { "displayName": "Interactive Sensitive Buldings Select", - "files": ["openlayers-sensitive/interactive-sensitive.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-sensitive/openlayers.css", "openlayers-sensitive/openlayers.html"], + "files": ["openlayers-sensitive/interactive-sensitive.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "config/vector-config.js", "openlayers-sensitive/openlayers.css", "openlayers-sensitive/openlayers.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -50,7 +50,7 @@ }, "Debug Layer": { "displayName": "DebugLayer", - "files": ["openlayers-debug-layer/debug-layer.js", "config/common-config.js", "config/raster-config.js", "openlayers-debug-layer/openlayers.css", "openlayers-debug-layer/openlayers.html"], + "files": ["openlayers-debug-layer/debug-layer.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "openlayers-debug-layer/openlayers.css", "openlayers-debug-layer/openlayers.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -58,7 +58,7 @@ }, "DrawAndModify": { "displayName": "Draw and Modify Geodesic", - "files": ["openlayers-draw-and-modify/draw-and-modify.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-draw-and-modify/draw-and-modify.css", "openlayers-draw-and-modify/draw-and-modify.html"], + "files": ["openlayers-draw-and-modify/draw-and-modify.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "config/vector-config.js", "openlayers-draw-and-modify/draw-and-modify.css", "openlayers-draw-and-modify/draw-and-modify.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -66,7 +66,7 @@ }, "PreloadTiles": { "displayName": "Preload Tiles", - "files": ["openlayers-preload/preload.js", "config/common-config.js", "config/raster-config.js", "openlayers-preload/preload.css", "openlayers-preload/preload.html"], + "files": ["openlayers-preload/preload.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "openlayers-preload/preload.css", "openlayers-preload/preload.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -74,7 +74,7 @@ }, "DrawStreetLabels": { "displayName": "Draw Street Labels", - "files": ["openlayers-street-labels/street-labels.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "openlayers-street-labels/street-labels.css", "openlayers-street-labels/street-labels.html"], + "files": ["openlayers-street-labels/street-labels.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "config/vector-config.js", "openlayers-street-labels/street-labels.css", "openlayers-street-labels/street-labels.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -82,7 +82,7 @@ }, "ol-ext": { "displayName": "ol-ext", - "files": ["ol-ext-example/ol-ext.js", "config/common-config.js", "config/raster-config.js", "ol-ext-example/openlayers.css", "ol-ext-example/openlayers.html"], + "files": ["ol-ext-example/ol-ext.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/xml-utils.js", "ol-ext-example/openlayers.css", "ol-ext-example/openlayers.html"], "links": [ { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } @@ -90,10 +90,10 @@ ] } }, - "cesium": { + "Cesium": { "WMTS" : { "displayName": "WMTS Imagery Provider", - "files": ["cesium-wmts/cesium.js", "config/common-config.js", "config/raster-config.js", "cesium-wmts/cesium.html"], + "files": ["cesium-wmts/cesium.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/wmts-utils.js", "utils/xml-utils.js", "cesium-wmts/cesium.html"], "links": [ { "name": "cesium.js", @@ -109,7 +109,7 @@ }, "GeoCoding" : { "displayName": "GeoCoding", - "files": ["cesium-geocoding/cesium.js", "config/common-config.js", "config/raster-config.js", "config/vector-config.js", "cesium-geocoding/cesium.html"], + "files": ["cesium-geocoding/cesium.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/wmts-utils.js", "utils/xml-utils.js", "config/vector-config.js", "cesium-geocoding/cesium.html"], "links": [ { "name": "cesium.js", @@ -125,7 +125,7 @@ }, "Terrain" : { "displayName": "Terrain Provider", - "files": ["cesium-terrain/cesium.js", "config/common-config.js", "config/raster-config.js", "config/dem-config.js", "cesium-terrain/cesium.html"], + "files": ["cesium-terrain/cesium.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/wmts-utils.js", "utils/xml-utils.js", "config/dem-config.js", "cesium-terrain/cesium.html"], "links": [ { "name": "cesium.js", @@ -141,7 +141,7 @@ }, "3D Model": { "displayName": "3D Model (South Lebanon)", - "files": ["cesium-3d/3d-model.js", "config/common-config.js", "config/raster-config.js", "config/3d-config.js", "config/dem-config.js", "cesium-3d/cesium.html"], + "files": ["cesium-3d/3d-model.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/wmts-utils.js", "utils/xml-utils.js", "config/3d-config.js", "config/dem-config.js", "cesium-3d/cesium.html"], "links": [ { "name": "cesium.js", @@ -157,7 +157,7 @@ }, "LayersSplit" : { "displayName": "Layers Split", - "files": ["cesium-layers-split/split-layers.js", "config/common-config.js", "config/raster-config.js", "cesium-layers-split/split-layers.html", "cesium-layers-split/split-layers.css"], + "files": ["cesium-layers-split/split-layers.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/wmts-utils.js", "utils/xml-utils.js", "cesium-layers-split/split-layers.html", "cesium-layers-split/split-layers.css"], "links": [ { "name": "cesium.js", @@ -173,7 +173,7 @@ }, "ViewShed" : { "displayName": "ViewShed", - "files": ["cesium-viewshed/viewshed.js", "config/common-config.js", "config/raster-config.js", "config/3d-config.js", "config/dem-config.js", "cesium-viewshed/viewshed.html", "cesium-viewshed/viewshed.css"], + "files": ["cesium-viewshed/viewshed.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/wmts-utils.js", "utils/xml-utils.js", "config/3d-config.js", "config/dem-config.js", "cesium-viewshed/viewshed.html", "cesium-viewshed/viewshed.css"], "links": [ { "name": "cesium.js", @@ -188,10 +188,10 @@ ] } }, - "leaflet": { + "Leaflet": { "WMTS": { "displayName": "Basic WMTS Example", - "files": ["leaflet-wmts/wmts.js", "config/common-config.js", "config/raster-config.js", "leaflet-wmts/leaflet.css", "leaflet-wmts/leaflet.html"], + "files": ["leaflet-wmts/wmts.js", "config/common-config.js", "config/raster-config.js", "utils/catalog-client.js", "utils/wmts-utils.js", "utils/xml-utils.js", "leaflet-wmts/leaflet.css", "leaflet-wmts/leaflet.html"], "links": [ { "name": "leaflet.js", diff --git a/examples/leaflet-wmts/wmts.js b/examples/leaflet-wmts/wmts.js index fb11034..0536b95 100644 --- a/examples/leaflet-wmts/wmts.js +++ b/examples/leaflet-wmts/wmts.js @@ -1,15 +1,16 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; const parser = (urlTemplate) => { return urlTemplate.replace("{TileMatrixSet}", "WorldCRS84").replace("{TileMatrix}", "{z}").replace("{TileRow}", "{y}").replace("{TileCol}", "{x}"); } -const urlTemplate = WMTS_URL; -const parsedUrl = parser(urlTemplate); - - +const layerName = `${PRODUCT_ID}-${PRODUCT_TYPE}`; const map = L.map('map', { crs: L.CRS.EPSG4326 }).setView([0.0, 0.0], 1); -const layer = L.tileLayer(parsedUrl + `?token=${TOKEN}`, { id: LAYER_NAME }); -map.addLayer(layer); +fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE).then(urlTemplate => { + const parsedUrl = parser(urlTemplate); + const layer = L.tileLayer(parsedUrl + `?token=${TOKEN}`, { id: layerName }); + map.addLayer(layer); +}); diff --git a/examples/ol-ext-example/ol-ext.js b/examples/ol-ext-example/ol-ext.js index b9386c4..51d68f5 100644 --- a/examples/ol-ext-example/ol-ext.js +++ b/examples/ol-ext-example/ol-ext.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ target: 'map', @@ -12,12 +13,13 @@ const map = new ol.Map({ const WMTSParser = new ol.format.WMTSCapabilities(); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-box-selection/box-selection.js b/examples/openlayers-box-selection/box-selection.js index 0d52ba7..68082b5 100644 --- a/examples/openlayers-box-selection/box-selection.js +++ b/examples/openlayers-box-selection/box-selection.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -140,12 +141,13 @@ selectedFeatures.on(['add', 'remove'], function () { } }); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-debug-layer/debug-layer.js b/examples/openlayers-debug-layer/debug-layer.js index dc4e09f..7d525c1 100644 --- a/examples/openlayers-debug-layer/debug-layer.js +++ b/examples/openlayers-debug-layer/debug-layer.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ target: 'map', @@ -12,12 +13,13 @@ const map = new ol.Map({ const WMTSParser = new ol.format.WMTSCapabilities(); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.js b/examples/openlayers-draw-and-modify/draw-and-modify.js index 6e1c683..2b15957 100644 --- a/examples/openlayers-draw-and-modify/draw-and-modify.js +++ b/examples/openlayers-draw-and-modify/draw-and-modify.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ layers: [], @@ -176,12 +177,13 @@ typeSelect.onchange = function () { addInteractions(); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-overview-map/overview-map.js b/examples/openlayers-overview-map/overview-map.js index 759d4a7..70c66b6 100644 --- a/examples/openlayers-overview-map/overview-map.js +++ b/examples/openlayers-overview-map/overview-map.js @@ -1,17 +1,20 @@ import { TOKEN } from './config/common-config.js'; -import { WMTS_CAPABILITIES_URL, LAYER_NAME, ADDITIONAL_LAYER_NAME } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); +const layerName = `${PRODUCT_ID}-${PRODUCT_TYPE}`; -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: layerName }); const optionsMiniMap = ol.source.WMTS.optionsFromCapabilities(results, { - layer: ADDITIONAL_LAYER_NAME + layer: layerName }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-permalink/permalink.js b/examples/openlayers-permalink/permalink.js index beddf5a..bdbf403 100644 --- a/examples/openlayers-permalink/permalink.js +++ b/examples/openlayers-permalink/permalink.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; // default zoom, center and rotation let zoom = 2; @@ -19,12 +20,13 @@ if (window.location.hash !== '') { const WMTSParser = new ol.format.WMTSCapabilities(); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-preload/preload.js b/examples/openlayers-preload/preload.js index 319c452..b4fcd17 100644 --- a/examples/openlayers-preload/preload.js +++ b/examples/openlayers-preload/preload.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -9,12 +10,13 @@ const sharedView = new ol.View({ projection: 'EPSG:4326', }); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-query-service/query-service.js b/examples/openlayers-query-service/query-service.js index 0ffeb64..fab02e0 100644 --- a/examples/openlayers-query-service/query-service.js +++ b/examples/openlayers-query-service/query-service.js @@ -1,6 +1,7 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; import { VECTOR_WFS_URL } from './config/vector-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ target: 'map', @@ -36,12 +37,13 @@ let rasterLayer; }); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-sensitive/interactive-sensitive.js b/examples/openlayers-sensitive/interactive-sensitive.js index a6db95b..97ee2d6 100644 --- a/examples/openlayers-sensitive/interactive-sensitive.js +++ b/examples/openlayers-sensitive/interactive-sensitive.js @@ -1,6 +1,7 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; import { VECTOR_WFS_URL } from './config/vector-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); let rasterLayer; @@ -75,12 +76,13 @@ selectedFeatures.on(['add', 'remove'], function () { } }); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-street-labels/street-labels.js b/examples/openlayers-street-labels/street-labels.js index bd0dc4f..93ada41 100644 --- a/examples/openlayers-street-labels/street-labels.js +++ b/examples/openlayers-street-labels/street-labels.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); let rasterLayer; @@ -53,12 +54,13 @@ const map = new ol.Map({ -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-wmts/wmts.js b/examples/openlayers-wmts/wmts.js index eee1023..ffedff6 100644 --- a/examples/openlayers-wmts/wmts.js +++ b/examples/openlayers-wmts/wmts.js @@ -1,5 +1,6 @@ import { TOKEN } from './config/common-config.js'; -import { LAYER_NAME, WMTS_CAPABILITIES_URL } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -12,12 +13,13 @@ const map = new ol.Map({ }), }); -fetch(WMTS_CAPABILITIES_URL) +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') + .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: LAYER_NAME + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, }); options.urls = options.urls.map(url => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/utils/catalog-client.js b/examples/utils/catalog-client.js new file mode 100644 index 0000000..7bc4751 --- /dev/null +++ b/examples/utils/catalog-client.js @@ -0,0 +1,68 @@ +import { MAPCOLONIES_CATALOG_URL, TOKEN } from './config/common-config.js'; +import { parseXml } from './utils/xml-utils.js'; + +const TYPENAMES = { + raster: 'mc:MCRasterRecord', + '3d': 'mc:MC3DRecord', + dem: 'mc:MCDEMRecord', +}; + +const namespaceFor = (catalogKey) => `http://schema.mapcolonies.com/${catalogKey}`; + +function buildGetRecordsBody(typename, namespace, productId, productType) { + return ` + + + full + + + + + mc:productId + ${productId} + + + mc:productType + ${productType} + + + + + +`; +} + +function parseLinks(xmlText, namespace) { + const doc = parseXml(xmlText, 'CSW response'); + return Array.from(doc.getElementsByTagNameNS(namespace, 'links')).reduce((acc, node) => { + const scheme = node.getAttribute('scheme'); + if (scheme) acc[scheme] = (node.textContent || '').trim(); + return acc; + }, {}); +} + +export async function fetchRecordLinks(catalogKey, productId, productType) { + const typename = TYPENAMES[catalogKey]; + if (!typename) throw new Error(`Unknown catalog: ${catalogKey}`); + const namespace = namespaceFor(catalogKey); + const res = await fetch(`${MAPCOLONIES_CATALOG_URL}/api/${catalogKey}/v1/csw`, { + method: 'POST', + headers: { 'Content-Type': 'application/xml', 'x-api-key': TOKEN }, + body: buildGetRecordsBody(typename, namespace, productId, productType), + }); + if (!res.ok) { + throw new Error(`CSW ${catalogKey} ${productId} failed: ${res.status}`); + } + return parseLinks(await res.text(), namespace); +} + +export async function fetchServiceLink(catalogKey, productId, productType, scheme) { + const links = await fetchRecordLinks(catalogKey, productId, productType); + const url = links[scheme]; + if (!url) { + throw new Error( + `No "${scheme}" link in ${catalogKey}/${productId}. Available: ${Object.keys(links).join(', ')}` + ); + } + return url; +} diff --git a/examples/utils/wmts-utils.js b/examples/utils/wmts-utils.js new file mode 100644 index 0000000..1d63220 --- /dev/null +++ b/examples/utils/wmts-utils.js @@ -0,0 +1,34 @@ +import { TOKEN } from './config/common-config.js'; +import { fetchServiceLink } from './utils/catalog-client.js'; +import { parseXml } from './utils/xml-utils.js'; + +const WMTS_NS = 'http://www.opengis.net/wmts/1.0'; +const OWS_NS = 'http://www.opengis.net/ows/1.1'; + +export function extractWmtsTileTemplate(capabilitiesXml, layerName, format) { + const doc = parseXml(capabilitiesXml, 'WMTS capabilities'); + const layer = Array.from(doc.getElementsByTagNameNS(WMTS_NS, 'Layer')).find(node => { + const identifier = node.getElementsByTagNameNS(OWS_NS, 'Identifier')[0]; + return identifier && identifier.textContent.trim() === layerName; + }); + if (!layer) { + throw new Error(`Layer "${layerName}" not found in WMTS capabilities`); + } + const resourceUrl = Array.from(layer.getElementsByTagNameNS(WMTS_NS, 'ResourceURL')).find(node => + node.getAttribute('resourceType') === 'tile' && + (!format || node.getAttribute('format') === format) + ); + if (!resourceUrl) { + throw new Error(`No tile ResourceURL for layer "${layerName}"`); + } + return resourceUrl.getAttribute('template'); +} + +export async function fetchWmtsTileTemplate(productId, productType, format) { + const capabilitiesUrl = await fetchServiceLink('raster', productId, productType, 'WMTS'); + const res = await fetch(`${capabilitiesUrl}?token=${TOKEN}`); + if (!res.ok) { + throw new Error(`Fetching WMTS capabilities failed: ${res.status}`); + } + return extractWmtsTileTemplate(await res.text(), `${productId}-${productType}`, format); +} diff --git a/examples/utils/xml-utils.js b/examples/utils/xml-utils.js new file mode 100644 index 0000000..09330af --- /dev/null +++ b/examples/utils/xml-utils.js @@ -0,0 +1,8 @@ +export function parseXml(xmlText, context) { + const doc = new DOMParser().parseFromString(xmlText, 'application/xml'); + const parseError = doc.getElementsByTagName('parsererror')[0]; + if (parseError) { + throw new Error(`${context} parse error: ${parseError.textContent}`); + } + return doc; +} diff --git a/package-lock.json b/package-lock.json index f2d0932..42eb45e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3032,9 +3032,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001488", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz", - "integrity": "sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -3049,7 +3049,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/cesium": { "version": "1.105.2", diff --git a/package.json b/package.json index 7bcce76..7f4a5a6 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,8 @@ "eslint-config-prettier": "^8.5.0", "eslint-plugin-svelte": "^2.26.0", "fast-equals": "^5.0.1", + "flowbite": "^1.6.5", + "flowbite-svelte": "^0.35.4", "micro-memoize": "^4.1.2", "postcss": "^8.4.23", "postcss-load-config": "^4.0.1", @@ -38,16 +40,14 @@ "tslib": "^2.4.1", "typescript": "^5.0.0", "vite": "^4.3.0", - "vite-plugin-static-copy": "^0.15.0", - "flowbite": "^1.6.5", - "flowbite-svelte": "^0.35.4" + "vite-plugin-static-copy": "^0.15.0" }, "type": "module", "dependencies": { "@aws-sdk/client-s3": "^3.335.0", "@popperjs/core": "^2.11.7", + "ajv": "^8.12.0", "async-cache-dedupe": "^1.12.0", - "classnames": "^2.3.2", - "ajv": "^8.12.0" + "classnames": "^2.3.2" } } From 8f0d2b0a1786f53508a26aef21ff4f91622e0b3c Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Fri, 5 Jun 2026 13:35:16 +0300 Subject: [PATCH 07/21] refactor: move schemes to config files --- examples/cesium-3d/3d-model.js | 8 ++++---- examples/cesium-terrain/cesium.js | 4 ++-- examples/cesium-viewshed/viewshed.js | 8 ++++---- examples/config/3d-config.js | 1 + examples/config/dem-config.js | 1 + examples/config/raster-config.js | 1 + examples/ol-ext-example/ol-ext.js | 4 ++-- examples/openlayers-box-selection/box-selection.js | 4 ++-- examples/openlayers-debug-layer/debug-layer.js | 4 ++-- examples/openlayers-draw-and-modify/draw-and-modify.js | 4 ++-- examples/openlayers-overview-map/overview-map.js | 4 ++-- examples/openlayers-permalink/permalink.js | 4 ++-- examples/openlayers-preload/preload.js | 4 ++-- examples/openlayers-query-service/query-service.js | 4 ++-- examples/openlayers-sensitive/interactive-sensitive.js | 4 ++-- examples/openlayers-street-labels/street-labels.js | 4 ++-- examples/openlayers-wmts/wmts.js | 4 ++-- examples/utils/wmts-utils.js | 3 ++- 18 files changed, 37 insertions(+), 33 deletions(-) diff --git a/examples/cesium-3d/3d-model.js b/examples/cesium-3d/3d-model.js index dffefbb..242ee2f 100644 --- a/examples/cesium-3d/3d-model.js +++ b/examples/cesium-3d/3d-model.js @@ -1,14 +1,14 @@ import { TOKEN } from './config/common-config.js'; import { PRODUCT_ID as RASTER_PRODUCT_ID, PRODUCT_TYPE as RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; -import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE } from './config/dem-config.js'; -import { PRODUCT_ID as MODEL_3D_PRODUCT_ID, PRODUCT_TYPE as MODEL_3D_PRODUCT_TYPE } from './config/3d-config.js'; +import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE, DEM_SCHEME } from './config/dem-config.js'; +import { PRODUCT_ID as MODEL_3D_PRODUCT_ID, PRODUCT_TYPE as MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME } from './config/3d-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; Promise.all([ fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), - fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, 'WCS'), - fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, '3DTiles'), + fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, DEM_SCHEME), + fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME), ]).then(([tileTemplate, demUrl, modelUrl]) => { const viewer = new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ diff --git a/examples/cesium-terrain/cesium.js b/examples/cesium-terrain/cesium.js index b303d62..1369679 100644 --- a/examples/cesium-terrain/cesium.js +++ b/examples/cesium-terrain/cesium.js @@ -1,12 +1,12 @@ import { TOKEN } from './config/common-config.js'; import { PRODUCT_ID as RASTER_PRODUCT_ID, PRODUCT_TYPE as RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; -import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE } from './config/dem-config.js'; +import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE, DEM_SCHEME } from './config/dem-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; Promise.all([ fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), - fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, 'WCS'), + fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, DEM_SCHEME), ]).then(([tileTemplate, demUrl]) => { const viewer = new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ diff --git a/examples/cesium-viewshed/viewshed.js b/examples/cesium-viewshed/viewshed.js index a422541..678fd81 100644 --- a/examples/cesium-viewshed/viewshed.js +++ b/examples/cesium-viewshed/viewshed.js @@ -1,7 +1,7 @@ import { TOKEN } from './config/common-config.js'; import { PRODUCT_ID as RASTER_PRODUCT_ID, PRODUCT_TYPE as RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; -import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE } from './config/dem-config.js'; -import { PRODUCT_ID as MODEL_3D_PRODUCT_ID, PRODUCT_TYPE as MODEL_3D_PRODUCT_TYPE } from './config/3d-config.js'; +import { PRODUCT_ID as DEM_PRODUCT_ID, PRODUCT_TYPE as DEM_PRODUCT_TYPE, DEM_SCHEME } from './config/dem-config.js'; +import { PRODUCT_ID as MODEL_3D_PRODUCT_ID, PRODUCT_TYPE as MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME } from './config/3d-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; @@ -595,8 +595,8 @@ let pointB = Cesium.Cartesian3.fromDegrees( let viewer; Promise.all([ fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), - fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, 'WCS'), - fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, '3DTiles'), + fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, DEM_SCHEME), + fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME), ]).then(([tileTemplate, demUrl, modelUrl]) => { viewer = new Cesium.Viewer("cesiumContainer", { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ diff --git a/examples/config/3d-config.js b/examples/config/3d-config.js index 7e9382c..a37e778 100644 --- a/examples/config/3d-config.js +++ b/examples/config/3d-config.js @@ -1,5 +1,6 @@ import { MAPCOLONIES_TILES_URL } from './config/common-config.js'; +export var MODEL_3D_SCHEME = '3DTiles'; export var PRODUCT_ID = 'd03ee59f-1676-4059-84cb-a0f68f15aefe'; export var PRODUCT_TYPE = '3DPhotoRealistic'; export var MODEL_3D_URL = `${MAPCOLONIES_TILES_URL}/api/3d/v1/b3dm/${PRODUCT_ID}/tileset.json`; diff --git a/examples/config/dem-config.js b/examples/config/dem-config.js index 36d144c..a8159de 100644 --- a/examples/config/dem-config.js +++ b/examples/config/dem-config.js @@ -1,5 +1,6 @@ import { MAPCOLONIES_TILES_URL } from './config/common-config.js'; +export var DEM_SCHEME = 'WCS'; export var PRODUCT_ID = 'srtm_100_30-aoi'; export var PRODUCT_TYPE = 'DTM'; export var DEM_URL = `${MAPCOLONIES_TILES_URL}/api/dem/v1/terrains/${PRODUCT_ID}`; diff --git a/examples/config/raster-config.js b/examples/config/raster-config.js index f07df1f..e697243 100644 --- a/examples/config/raster-config.js +++ b/examples/config/raster-config.js @@ -2,6 +2,7 @@ import { MAPCOLONIES_TILES_URL, TOKEN } from './config/common-config.js'; var WMTS_BASE_URL = `${MAPCOLONIES_TILES_URL}/api/raster/v1/wmts`; +export var RASTER_SCHEME = 'WMTS'; export var PRODUCT_ID = 'blueMarble'; export var PRODUCT_TYPE = 'Orthophoto'; export var LAYER_NAME = `${PRODUCT_ID}-${PRODUCT_TYPE}`; diff --git a/examples/ol-ext-example/ol-ext.js b/examples/ol-ext-example/ol-ext.js index 51d68f5..f615cf0 100644 --- a/examples/ol-ext-example/ol-ext.js +++ b/examples/ol-ext-example/ol-ext.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ @@ -13,7 +13,7 @@ const map = new ol.Map({ const WMTSParser = new ol.format.WMTSCapabilities(); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-box-selection/box-selection.js b/examples/openlayers-box-selection/box-selection.js index 68082b5..1150e17 100644 --- a/examples/openlayers-box-selection/box-selection.js +++ b/examples/openlayers-box-selection/box-selection.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -141,7 +141,7 @@ selectedFeatures.on(['add', 'remove'], function () { } }); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-debug-layer/debug-layer.js b/examples/openlayers-debug-layer/debug-layer.js index 7d525c1..174b360 100644 --- a/examples/openlayers-debug-layer/debug-layer.js +++ b/examples/openlayers-debug-layer/debug-layer.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ @@ -13,7 +13,7 @@ const map = new ol.Map({ const WMTSParser = new ol.format.WMTSCapabilities(); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.js b/examples/openlayers-draw-and-modify/draw-and-modify.js index 2b15957..f962f6b 100644 --- a/examples/openlayers-draw-and-modify/draw-and-modify.js +++ b/examples/openlayers-draw-and-modify/draw-and-modify.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ @@ -177,7 +177,7 @@ typeSelect.onchange = function () { addInteractions(); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-overview-map/overview-map.js b/examples/openlayers-overview-map/overview-map.js index 70c66b6..d43f298 100644 --- a/examples/openlayers-overview-map/overview-map.js +++ b/examples/openlayers-overview-map/overview-map.js @@ -1,11 +1,11 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); const layerName = `${PRODUCT_ID}-${PRODUCT_TYPE}`; -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-permalink/permalink.js b/examples/openlayers-permalink/permalink.js index bdbf403..81730eb 100644 --- a/examples/openlayers-permalink/permalink.js +++ b/examples/openlayers-permalink/permalink.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; // default zoom, center and rotation @@ -20,7 +20,7 @@ if (window.location.hash !== '') { const WMTSParser = new ol.format.WMTSCapabilities(); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-preload/preload.js b/examples/openlayers-preload/preload.js index b4fcd17..b1989ee 100644 --- a/examples/openlayers-preload/preload.js +++ b/examples/openlayers-preload/preload.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -10,7 +10,7 @@ const sharedView = new ol.View({ projection: 'EPSG:4326', }); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-query-service/query-service.js b/examples/openlayers-query-service/query-service.js index fab02e0..2e40ac3 100644 --- a/examples/openlayers-query-service/query-service.js +++ b/examples/openlayers-query-service/query-service.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { VECTOR_WFS_URL } from './config/vector-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; @@ -37,7 +37,7 @@ let rasterLayer; }); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-sensitive/interactive-sensitive.js b/examples/openlayers-sensitive/interactive-sensitive.js index 97ee2d6..ee0dad5 100644 --- a/examples/openlayers-sensitive/interactive-sensitive.js +++ b/examples/openlayers-sensitive/interactive-sensitive.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { VECTOR_WFS_URL } from './config/vector-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; @@ -76,7 +76,7 @@ selectedFeatures.on(['add', 'remove'], function () { } }); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-street-labels/street-labels.js b/examples/openlayers-street-labels/street-labels.js index 93ada41..140a8a2 100644 --- a/examples/openlayers-street-labels/street-labels.js +++ b/examples/openlayers-street-labels/street-labels.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -54,7 +54,7 @@ const map = new ol.Map({ -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/openlayers-wmts/wmts.js b/examples/openlayers-wmts/wmts.js index ffedff6..1144b71 100644 --- a/examples/openlayers-wmts/wmts.js +++ b/examples/openlayers-wmts/wmts.js @@ -1,5 +1,5 @@ import { TOKEN } from './config/common-config.js'; -import { PRODUCT_ID, PRODUCT_TYPE } from './config/raster-config.js'; +import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); @@ -13,7 +13,7 @@ const map = new ol.Map({ }), }); -fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, 'WMTS') +fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) .then(url => fetch(`${url}?token=${TOKEN}`)) .then(response => response.text()) .then(text => { diff --git a/examples/utils/wmts-utils.js b/examples/utils/wmts-utils.js index 1d63220..eed5237 100644 --- a/examples/utils/wmts-utils.js +++ b/examples/utils/wmts-utils.js @@ -1,4 +1,5 @@ import { TOKEN } from './config/common-config.js'; +import { RASTER_SCHEME } from './config/raster-config.js'; import { fetchServiceLink } from './utils/catalog-client.js'; import { parseXml } from './utils/xml-utils.js'; @@ -25,7 +26,7 @@ export function extractWmtsTileTemplate(capabilitiesXml, layerName, format) { } export async function fetchWmtsTileTemplate(productId, productType, format) { - const capabilitiesUrl = await fetchServiceLink('raster', productId, productType, 'WMTS'); + const capabilitiesUrl = await fetchServiceLink('raster', productId, productType, RASTER_SCHEME); const res = await fetch(`${capabilitiesUrl}?token=${TOKEN}`); if (!res.ok) { throw new Error(`Fetching WMTS capabilities failed: ${res.status}`); From 114fe3d5c717c6446ed8c673f49ba28a32f82f65 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Fri, 5 Jun 2026 17:13:22 +0300 Subject: [PATCH 08/21] feat: highlight active demo --- src/lib/components/bottomBar.svelte | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/lib/components/bottomBar.svelte b/src/lib/components/bottomBar.svelte index f0017d8..1343a49 100644 --- a/src/lib/components/bottomBar.svelte +++ b/src/lib/components/bottomBar.svelte @@ -7,6 +7,7 @@ BottomNavHeaderItem } from 'flowbite-svelte'; import { goto } from '$app/navigation'; + import { page } from '$app/stores'; import BottomHeaderItem from './bottomHeaderItem.svelte'; import classNames from 'classnames'; @@ -14,6 +15,8 @@ export let items: { name: string; displayName?: string }[]; export let activeClient: string | undefined; + $: activeItem = $page.params.name; + $: outerDiv = classNames('-translate-x-0', 'dark:bg-gray-800', $$props.outerDiv); @@ -41,7 +44,12 @@ goto('/demo/' + activeClient + '/' + item.name)} id="group-{item.name}" - btnDefault="basis-0 items-center justify-center ml-[4px] mb-1 bg-gray-100 dark:bg-gray-600 rounded-lg p-4 text-gray-900 hover:bg-gray-200 dark:text-white dark:hover:bg-gray-700 group" + btnDefault={classNames( + 'basis-0 items-center justify-center ml-[4px] mb-1 rounded-lg p-4 group', + item.name === activeItem + ? 'bg-blue-600 text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600' + : 'bg-gray-100 dark:bg-gray-600 text-gray-900 hover:bg-gray-200 dark:text-white dark:hover:bg-gray-700' + )} > {item.displayName || item.name} C; B-->D; C-->D; -``` \ No newline at end of file +``` diff --git a/examples/ol-ext-example/ol-ext.js b/examples/ol-ext-example/ol-ext.js index f615cf0..97978d0 100644 --- a/examples/ol-ext-example/ol-ext.js +++ b/examples/ol-ext-example/ol-ext.js @@ -7,21 +7,21 @@ const map = new ol.Map({ view: new ol.View({ center: [0, 0], zoom: 0, - projection: 'EPSG:4326', - }), + projection: 'EPSG:4326' + }) }); const WMTSParser = new ol.format.WMTSCapabilities(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); const layer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); diff --git a/examples/ol-ext-example/openlayers.css b/examples/ol-ext-example/openlayers.css index dcac999..3e6b562 100644 --- a/examples/ol-ext-example/openlayers.css +++ b/examples/ol-ext-example/openlayers.css @@ -1,6 +1,6 @@ #map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; + position: absolute; + top: 0; + bottom: 0; + width: 100%; } diff --git a/examples/openlayers-box-selection/box-selection.html b/examples/openlayers-box-selection/box-selection.html index a03aaed..e5bbe55 100644 --- a/examples/openlayers-box-selection/box-selection.html +++ b/examples/openlayers-box-selection/box-selection.html @@ -1,13 +1,21 @@ -
-
-
-

Using a DragBox interaction to select features.

-

This example shows how to use a DragBox interaction to select features. Selected features are added to the feature overlay of a select interaction (ol/interaction/Select) for highlighting.

Use Ctrl+Drag (Command+Drag on Mac) to draw boxes.

-
-
- -
-

The selected Features are - -

-
\ No newline at end of file +
+
+
+

Using a DragBox interaction to select features.

+
+

+ This example shows how to use a DragBox interaction to select features. + Selected features are added to the feature overlay of a select interaction + (ol/interaction/Select) for highlighting. +

+

Use Ctrl+Drag (Command+Drag on Mac) to draw boxes.

+
+
+ +
+

+ The selected Features are + +

+
+
diff --git a/examples/openlayers-box-selection/box-selection.js b/examples/openlayers-box-selection/box-selection.js index 1150e17..1d84d73 100644 --- a/examples/openlayers-box-selection/box-selection.js +++ b/examples/openlayers-box-selection/box-selection.js @@ -5,56 +5,60 @@ import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); const vectorSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 256})), - url: function(extent) { - return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json`; - } + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({ tileSize: 256 })), + url: function (extent) { + return ( + VECTOR_WFS_URL + + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join( + ',' + )},EPSG:4326&token=${TOKEN}&outputFormat=application/json` + ); + } }); const style = new ol.style.Style({ - fill: new ol.style.Fill({ - color: '#eeeeee' - }), + fill: new ol.style.Fill({ + color: '#eeeeee' + }) }); const map = new ol.Map({ - target: 'map', - view: new ol.View({ - center: [34.465798, 31.513991], - zoom: 18, - projection: 'EPSG:4326', - constrainRotation: 16, - }), + target: 'map', + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + constrainRotation: 16 + }) }); const vectorLayer = new ol.layer.Vector({ - source: vectorSource, - style: function (feature) { - const color = feature.get('is_sensitive') === true ? 'red' : '#eeeeee'; - style.getFill().setColor(color); - return style; - }, - }) - + source: vectorSource, + style: function (feature) { + const color = feature.get('is_sensitive') === true ? 'red' : '#eeeeee'; + style.getFill().setColor(color); + return style; + } +}); const selectedStyle = new ol.style.Style({ - fill: new ol.style.Fill({ - color: 'rgba(180, 2, 180, 0.3)', - }), - stroke: new ol.style.Stroke({ - color: 'rgba(180, 2, 180, 0.4)', - width: 5, - }), + fill: new ol.style.Fill({ + color: 'rgba(180, 2, 180, 0.3)' + }), + stroke: new ol.style.Stroke({ + color: 'rgba(180, 2, 180, 0.4)', + width: 5 + }) }); // a normal select interaction to handle click const select = new ol.interaction.Select({ - style: function (feature) { - const color = feature.get('is_sensitive') === true ? 'red' : '#eeeeee'; - selectedStyle.getFill().setColor(color); - return selectedStyle; - }, + style: function (feature) { + const color = feature.get('is_sensitive') === true ? 'red' : '#eeeeee'; + selectedStyle.getFill().setColor(color); + return selectedStyle; + } }); map.addInteraction(select); @@ -62,98 +66,101 @@ const selectedFeatures = select.getFeatures(); // a DragBox interaction used to select features by drawing boxes const dragBox = new ol.interaction.DragBox({ - condition: ol.events.condition.platformModifierKeyOnly, + condition: ol.events.condition.platformModifierKeyOnly }); map.addInteraction(dragBox); dragBox.on('boxend', function () { - const boxExtent = dragBox.getGeometry().getExtent(); - - // if the extent crosses the antimeridian process each world separately - const worldExtent = map.getView().getProjection().getExtent(); - const worldWidth = ol.extent.getWidth(worldExtent); - const startWorld = Math.floor((boxExtent[0] - worldExtent[0]) / worldWidth); - const endWorld = Math.floor((boxExtent[2] - worldExtent[0]) / worldWidth); - - for (let world = startWorld; world <= endWorld; ++world) { - const left = Math.max(boxExtent[0] - world * worldWidth, worldExtent[0]); - const right = Math.min(boxExtent[2] - world * worldWidth, worldExtent[2]); - const extent = [left, boxExtent[1], right, boxExtent[3]]; - - const boxFeatures = vectorSource - .getFeaturesInExtent(extent) - .filter( - (feature) => - !selectedFeatures.getArray().includes(feature) && - feature.getGeometry().intersectsExtent(extent) - ); - - // features that intersect the box geometry are added to the - // collection of selected features - - // if the view is not obliquely rotated the box geometry and - // its extent are equalivalent so intersecting features can - // be added directly to the collection - const rotation = map.getView().getRotation(); - const oblique = rotation % (Math.PI / 2) !== 0; - - // when the view is obliquely rotated the box extent will - // exceed its geometry so both the box and the candidate - // feature geometries are rotated around a common anchor - // to confirm that, with the box geometry aligned with its - // extent, the geometries intersect - if (oblique) { - const anchor = [0, 0]; - const geometry = dragBox.getGeometry().clone(); - geometry.translate(-world * worldWidth, 0); - geometry.rotate(-rotation, anchor); - const extent = geometry.getExtent(); - boxFeatures.forEach(function (feature) { - const geometry = feature.getGeometry().clone(); - geometry.rotate(-rotation, anchor); - if (geometry.intersectsExtent(extent)) { - selectedFeatures.push(feature); - } - }); - } else { - selectedFeatures.extend(boxFeatures); - } - } + const boxExtent = dragBox.getGeometry().getExtent(); + + // if the extent crosses the antimeridian process each world separately + const worldExtent = map.getView().getProjection().getExtent(); + const worldWidth = ol.extent.getWidth(worldExtent); + const startWorld = Math.floor((boxExtent[0] - worldExtent[0]) / worldWidth); + const endWorld = Math.floor((boxExtent[2] - worldExtent[0]) / worldWidth); + + for (let world = startWorld; world <= endWorld; ++world) { + const left = Math.max(boxExtent[0] - world * worldWidth, worldExtent[0]); + const right = Math.min(boxExtent[2] - world * worldWidth, worldExtent[2]); + const extent = [left, boxExtent[1], right, boxExtent[3]]; + + const boxFeatures = vectorSource + .getFeaturesInExtent(extent) + .filter( + (feature) => + !selectedFeatures.getArray().includes(feature) && + feature.getGeometry().intersectsExtent(extent) + ); + + // features that intersect the box geometry are added to the + // collection of selected features + + // if the view is not obliquely rotated the box geometry and + // its extent are equalivalent so intersecting features can + // be added directly to the collection + const rotation = map.getView().getRotation(); + const oblique = rotation % (Math.PI / 2) !== 0; + + // when the view is obliquely rotated the box extent will + // exceed its geometry so both the box and the candidate + // feature geometries are rotated around a common anchor + // to confirm that, with the box geometry aligned with its + // extent, the geometries intersect + if (oblique) { + const anchor = [0, 0]; + const geometry = dragBox.getGeometry().clone(); + geometry.translate(-world * worldWidth, 0); + geometry.rotate(-rotation, anchor); + const extent = geometry.getExtent(); + boxFeatures.forEach(function (feature) { + const geometry = feature.getGeometry().clone(); + geometry.rotate(-rotation, anchor); + if (geometry.intersectsExtent(extent)) { + selectedFeatures.push(feature); + } + }); + } else { + selectedFeatures.extend(boxFeatures); + } + } }); // clear selection when drawing a new box and when clicking on the map dragBox.on('boxstart', function () { - selectedFeatures.clear(); + selectedFeatures.clear(); }); const infoBox = document.getElementById('info'); selectedFeatures.on(['add', 'remove'], function () { - const names = selectedFeatures.getArray().map((feature) => { - return { 'סוג מבנה': feature.get('building_type'), GFID: feature.get('entity_id'), 'רגיש': feature.get('is_sensitive') }; - }); - console.clear(); - if (names.length > 0) { - infoBox.innerHTML = JSON.stringify(names, 2, 4); - } else { - infoBox.innerHTML = 'None'; - } + const names = selectedFeatures.getArray().map((feature) => { + return { + 'סוג מבנה': feature.get('building_type'), + GFID: feature.get('entity_id'), + רגיש: feature.get('is_sensitive') + }; + }); + console.clear(); + if (names.length > 0) { + infoBox.innerHTML = JSON.stringify(names, 2, 4); + } else { + infoBox.innerHTML = 'None'; + } }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); const rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); map.addLayer(rasterLayer); - map.addLayer(vectorLayer); - -}); + map.addLayer(vectorLayer); + }); diff --git a/examples/openlayers-box-selection/openlayers.css b/examples/openlayers-box-selection/openlayers.css index 46a9541..72b367f 100644 --- a/examples/openlayers-box-selection/openlayers.css +++ b/examples/openlayers-box-selection/openlayers.css @@ -1,6 +1,6 @@ #map { - top: 0; - bottom: 0; - height: 50%; - width: 100%; + top: 0; + bottom: 0; + height: 50%; + width: 100%; } diff --git a/examples/openlayers-debug-layer/debug-layer.js b/examples/openlayers-debug-layer/debug-layer.js index 174b360..9811b59 100644 --- a/examples/openlayers-debug-layer/debug-layer.js +++ b/examples/openlayers-debug-layer/debug-layer.js @@ -7,34 +7,33 @@ const map = new ol.Map({ view: new ol.View({ center: [0, 0], zoom: 0, - projection: 'EPSG:4326', - }), + projection: 'EPSG:4326' + }) }); const WMTSParser = new ol.format.WMTSCapabilities(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); const layer = new ol.layer.WebGLTile({ opacity: 1, source: new ol.source.WMTS(options) }); map.addLayer(layer); - const debugLayer = new ol.layer.WebGLTile({ - source: new ol.source.TileDebug({ - template: 'z:{z} x:{x}, y:{y}', - projection: layer.getSource().getProjection(), - tileGrid: layer.getSource().getTileGrid(), - zDirection: 1 - }) - }); - map.addLayer(debugLayer); - + const debugLayer = new ol.layer.WebGLTile({ + source: new ol.source.TileDebug({ + template: 'z:{z} x:{x}, y:{y}', + projection: layer.getSource().getProjection(), + tileGrid: layer.getSource().getTileGrid(), + zDirection: 1 + }) + }); + map.addLayer(debugLayer); }); diff --git a/examples/openlayers-debug-layer/openlayers.css b/examples/openlayers-debug-layer/openlayers.css index dcac999..3e6b562 100644 --- a/examples/openlayers-debug-layer/openlayers.css +++ b/examples/openlayers-debug-layer/openlayers.css @@ -1,6 +1,6 @@ #map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; + position: absolute; + top: 0; + bottom: 0; + width: 100%; } diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.css b/examples/openlayers-draw-and-modify/draw-and-modify.css index 1e20f5c..110b53a 100644 --- a/examples/openlayers-draw-and-modify/draw-and-modify.css +++ b/examples/openlayers-draw-and-modify/draw-and-modify.css @@ -1,7 +1,6 @@ -#map { - height: 70%; - top: 0; - bottom: 0; - width: 100%; -} - \ No newline at end of file +#map { + height: 70%; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.html b/examples/openlayers-draw-and-modify/draw-and-modify.html index 40c95db..cae5273 100644 --- a/examples/openlayers-draw-and-modify/draw-and-modify.html +++ b/examples/openlayers-draw-and-modify/draw-and-modify.html @@ -1,16 +1,30 @@ -
-
- - -
- -
-

Example of using Draw and Modify interactions for geodesic circles.

-

Example of using the ol/interaction/Draw interaction with a custom geometry function together with the ol/interaction/Modify interaction to draw and modify geodesic circles (a ol/geom/Polygon#circular polygon representing a circle on the surface of the Earth's sphere). The polygon is placed in a ol/geom/GeometryCollection together with a ol/geom/Point which allows the Modify interaction to adjust the circle center as well as the radius. Custom style functions ensure the correct final geometry is displayed throughout. ol/geom/Circle projected (planar) geometries can also be drawn and modified. The difference between geodesic and projected circles can be seen when their centers are moved between northern and southern latitudes in the Web Mercator projection. The ol/interaction/Snap interaction can be used to create concentric circles.

-
\ No newline at end of file +
+
+ + +
+ +
+

Example of using Draw and Modify interactions for geodesic circles.

+
+

+ Example of using the ol/interaction/Draw interaction with a custom geometry + function together with the ol/interaction/Modify interaction to draw and modify + geodesic circles (a ol/geom/Polygon#circular polygon representing a circle on the + surface of the Earth's sphere). The polygon is placed in a + ol/geom/GeometryCollection together with a ol/geom/Point which + allows the Modify interaction to adjust the circle center as well as the radius. Custom style + functions ensure the correct final geometry is displayed throughout. + ol/geom/Circle projected (planar) geometries can also be drawn and modified. The + difference between geodesic and projected circles can be seen when their centers are moved + between northern and southern latitudes in the Web Mercator projection. The + ol/interaction/Snap interaction can be used to create concentric circles. +

+
+
diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.js b/examples/openlayers-draw-and-modify/draw-and-modify.js index f962f6b..59a6712 100644 --- a/examples/openlayers-draw-and-modify/draw-and-modify.js +++ b/examples/openlayers-draw-and-modify/draw-and-modify.js @@ -3,13 +3,13 @@ import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config. import { fetchServiceLink } from './utils/catalog-client.js'; const map = new ol.Map({ - layers: [], - target: 'map', - view: new ol.View({ - center: [0, 0], - zoom: 0, - projection: 'EPSG:4326', - }), + layers: [], + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 0, + projection: 'EPSG:4326' + }) }); const WMTSParser = new ol.format.WMTSCapabilities(); @@ -17,115 +17,107 @@ const WMTSParser = new ol.format.WMTSCapabilities(); const source = new ol.source.Vector(); const style = new ol.style.Style({ - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 255, 0.2)', - }), - stroke: new ol.style.Stroke({ - color: '#33cc33', - width: 2, - }), - image: new ol.style.Circle({ - radius: 7, - fill: new ol.style.Fill({ - color: '#ffcc33', - }), - }), + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }), + stroke: new ol.style.Stroke({ + color: '#33cc33', + width: 2 + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: '#ffcc33' + }) + }) }); const geodesicStyle = new ol.style.Style({ - geometry: function (feature) { - return feature.get('modifyGeometry') || feature.getGeometry(); - }, - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 255, 0.2)', - }), - stroke: new ol.style.Stroke({ - color: '#ff3333', - width: 2, - }), - image: new ol.style.Circle({ - radius: 7, - fill: new ol.style.Fill({ - color: 'rgba(0, 0, 0, 0)', - }), - }), + geometry: function (feature) { + return feature.get('modifyGeometry') || feature.getGeometry(); + }, + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)' + }), + stroke: new ol.style.Stroke({ + color: '#ff3333', + width: 2 + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: 'rgba(0, 0, 0, 0)' + }) + }) }); const vector = new ol.layer.Vector({ - source: source, - style: function (feature) { - const geometry = feature.getGeometry(); - return geometry.getType() === 'GeometryCollection' ? geodesicStyle : style; - }, + source: source, + style: function (feature) { + const geometry = feature.getGeometry(); + return geometry.getType() === 'GeometryCollection' ? geodesicStyle : style; + } }); - - -const defaultStyle = new ol.interaction.Modify({source: source}) - .getOverlay() - .getStyleFunction(); +const defaultStyle = new ol.interaction.Modify({ source: source }).getOverlay().getStyleFunction(); const modify = new ol.interaction.Modify({ - source: source, - style: function (feature) { - feature.get('features').forEach(function (modifyFeature) { - const modifyGeometry = modifyFeature.get('modifyGeometry'); - if (modifyGeometry) { - const modifyPoint = feature.getGeometry().getCoordinates(); - const geometries = modifyFeature.getGeometry().getGeometries(); - const polygon = geometries[0].getCoordinates()[0]; - const center = geometries[1].getCoordinates(); - const projection = map.getView().getProjection(); - let first, last, radius; - if (modifyPoint[0] === center[0] && modifyPoint[1] === center[1]) { - // center is being modified - // get unchanged radius from diameter between polygon vertices - first = ol.proj.transform(polygon[0], projection, 'EPSG:4326'); - last = ol.proj.transform( - polygon[(polygon.length - 1) / 2], - projection, - 'EPSG:4326' - ); - radius = ol.sphere.getDistance(first, last) / 2; - } else { - // radius is being modified - first = ol.proj.transform(center, projection, 'EPSG:4326'); - last = ol.proj.transform(modifyPoint, projection, 'EPSG:4326'); - radius = ol.sphere.getDistance(first, last); - } - // update the polygon using new center or radius - const circle = ol.geom.Circle( - ol.proj.transform(center, projection, 'EPSG:4326'), - radius, - 128 - ); - circle.transform('EPSG:4326', projection); - geometries[0].setCoordinates(circle.getCoordinates()); - // save changes to be applied at the end of the interaction - modifyGeometry.setGeometries(geometries); - } - }); - return defaultStyle(feature); - }, + source: source, + style: function (feature) { + feature.get('features').forEach(function (modifyFeature) { + const modifyGeometry = modifyFeature.get('modifyGeometry'); + if (modifyGeometry) { + const modifyPoint = feature.getGeometry().getCoordinates(); + const geometries = modifyFeature.getGeometry().getGeometries(); + const polygon = geometries[0].getCoordinates()[0]; + const center = geometries[1].getCoordinates(); + const projection = map.getView().getProjection(); + let first, last, radius; + if (modifyPoint[0] === center[0] && modifyPoint[1] === center[1]) { + // center is being modified + // get unchanged radius from diameter between polygon vertices + first = ol.proj.transform(polygon[0], projection, 'EPSG:4326'); + last = ol.proj.transform(polygon[(polygon.length - 1) / 2], projection, 'EPSG:4326'); + radius = ol.sphere.getDistance(first, last) / 2; + } else { + // radius is being modified + first = ol.proj.transform(center, projection, 'EPSG:4326'); + last = ol.proj.transform(modifyPoint, projection, 'EPSG:4326'); + radius = ol.sphere.getDistance(first, last); + } + // update the polygon using new center or radius + const circle = ol.geom.Circle( + ol.proj.transform(center, projection, 'EPSG:4326'), + radius, + 128 + ); + circle.transform('EPSG:4326', projection); + geometries[0].setCoordinates(circle.getCoordinates()); + // save changes to be applied at the end of the interaction + modifyGeometry.setGeometries(geometries); + } + }); + return defaultStyle(feature); + } }); modify.on('modifystart', function (event) { - event.features.forEach(function (feature) { - const geometry = feature.getGeometry(); - if (geometry.getType() === 'GeometryCollection') { - feature.set('modifyGeometry', geometry.clone(), true); - } - }); + event.features.forEach(function (feature) { + const geometry = feature.getGeometry(); + if (geometry.getType() === 'GeometryCollection') { + feature.set('modifyGeometry', geometry.clone(), true); + } + }); }); modify.on('modifyend', function (event) { - event.features.forEach(function (feature) { - const modifyGeometry = feature.get('modifyGeometry'); - if (modifyGeometry) { - feature.setGeometry(modifyGeometry); - feature.unset('modifyGeometry', true); - } - }); + event.features.forEach(function (feature) { + const modifyGeometry = feature.get('modifyGeometry'); + if (modifyGeometry) { + feature.setGeometry(modifyGeometry); + feature.unset('modifyGeometry', true); + } + }); }); map.addInteraction(modify); @@ -134,61 +126,61 @@ let draw, snap; // global so we can remove them later const typeSelect = document.getElementById('type'); function addInteractions() { - let value = typeSelect.value; - let geometryFunction; - if (value === 'Geodesic') { - value = 'Circle'; - geometryFunction = function (coordinates, geometry, projection) { - if (!geometry) { - geometry = new ol.geom.GeometryCollection([ - new ol.geom.Polygon([]), - new ol.geom.Point(coordinates[0]), - ]); - } - const geometries = geometry.getGeometries(); - const center = ol.proj.transform(coordinates[0], projection, 'EPSG:4326'); - const last = ol.proj.transform(coordinates[1], projection, 'EPSG:4326'); - const radius = ol.sphere.getDistance(center, last); - const circle = ol.geom.Polygon.circular(center, radius, 128); - circle.transform('EPSG:4326', projection); - geometries[0].setCoordinates(circle.getCoordinates()); - geometry.setGeometries(geometries); - return geometry; - }; - } - draw = new ol.interaction.Draw({ - source: source, - type: value, - geometryFunction: geometryFunction, - }); - map.addInteraction(draw); - snap = new ol.interaction.Snap({source: source}); - map.addInteraction(snap); + let value = typeSelect.value; + let geometryFunction; + if (value === 'Geodesic') { + value = 'Circle'; + geometryFunction = function (coordinates, geometry, projection) { + if (!geometry) { + geometry = new ol.geom.GeometryCollection([ + new ol.geom.Polygon([]), + new ol.geom.Point(coordinates[0]) + ]); + } + const geometries = geometry.getGeometries(); + const center = ol.proj.transform(coordinates[0], projection, 'EPSG:4326'); + const last = ol.proj.transform(coordinates[1], projection, 'EPSG:4326'); + const radius = ol.sphere.getDistance(center, last); + const circle = ol.geom.Polygon.circular(center, radius, 128); + circle.transform('EPSG:4326', projection); + geometries[0].setCoordinates(circle.getCoordinates()); + geometry.setGeometries(geometries); + return geometry; + }; + } + draw = new ol.interaction.Draw({ + source: source, + type: value, + geometryFunction: geometryFunction + }); + map.addInteraction(draw); + snap = new ol.interaction.Snap({ source: source }); + map.addInteraction(snap); } /** * Handle change event. */ typeSelect.onchange = function () { - map.removeInteraction(draw); - map.removeInteraction(snap); - addInteractions(); + map.removeInteraction(draw); + map.removeInteraction(snap); + addInteractions(); }; addInteractions(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { - const results = WMTSParser.read(text); - const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` - }); - options.urls = options.urls.map(url => { - return url.concat(`?token=${TOKEN}`); - }); - const layer = new ol.layer.WebGLTile({ opacity: 1, source: new ol.source.WMTS(options) }); - map.addLayer(layer); - map.addLayer(vector); - }); + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + }); + options.urls = options.urls.map((url) => { + return url.concat(`?token=${TOKEN}`); + }); + const layer = new ol.layer.WebGLTile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(layer); + map.addLayer(vector); + }); diff --git a/examples/openlayers-overview-map/overview-map.css b/examples/openlayers-overview-map/overview-map.css index 724d323..37d4727 100644 --- a/examples/openlayers-overview-map/overview-map.css +++ b/examples/openlayers-overview-map/overview-map.css @@ -1,40 +1,39 @@ -#map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; -} - - -.map .ol-custom-overviewmap, -.map .ol-custom-overviewmap.ol-uncollapsible { - bottom: auto; - left: auto; - right: 0; - top: 0; -} - -.map .ol-custom-overviewmap:not(.ol-collapsed) { - border: 1px solid black; -} - -.map .ol-custom-overviewmap .ol-overviewmap-map { - border: none; - width: 300px; -} - -.map .ol-custom-overviewmap .ol-overviewmap-box { - border: 2px solid red; -} - -.map .ol-custom-overviewmap:not(.ol-collapsed) button{ - bottom: auto; - left: auto; - right: 1px; - top: 1px; -} - -.map .ol-rotate { - top: 170px; - right: 0; -} +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} + +.map .ol-custom-overviewmap, +.map .ol-custom-overviewmap.ol-uncollapsible { + bottom: auto; + left: auto; + right: 0; + top: 0; +} + +.map .ol-custom-overviewmap:not(.ol-collapsed) { + border: 1px solid black; +} + +.map .ol-custom-overviewmap .ol-overviewmap-map { + border: none; + width: 300px; +} + +.map .ol-custom-overviewmap .ol-overviewmap-box { + border: 2px solid red; +} + +.map .ol-custom-overviewmap:not(.ol-collapsed) button { + bottom: auto; + left: auto; + right: 1px; + top: 1px; +} + +.map .ol-rotate { + top: 170px; + right: 0; +} diff --git a/examples/openlayers-overview-map/overview-map.html b/examples/openlayers-overview-map/overview-map.html index 2bc7f26..4fa1fbc 100644 --- a/examples/openlayers-overview-map/overview-map.html +++ b/examples/openlayers-overview-map/overview-map.html @@ -1 +1 @@ -
+
diff --git a/examples/openlayers-overview-map/overview-map.js b/examples/openlayers-overview-map/overview-map.js index d43f298..6956ca0 100644 --- a/examples/openlayers-overview-map/overview-map.js +++ b/examples/openlayers-overview-map/overview-map.js @@ -6,36 +6,45 @@ const WMTSParser = new ol.format.WMTSCapabilities(); const layerName = `${PRODUCT_ID}-${PRODUCT_TYPE}`; fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { - const results = WMTSParser.read(text); - const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: layerName - }); - const optionsMiniMap = ol.source.WMTS.optionsFromCapabilities(results, { - layer: layerName - }); - options.urls = options.urls.map(url => { - return url.concat(`?token=${TOKEN}`); - }); - optionsMiniMap.urls = optionsMiniMap.urls.map(url => { - return url.concat(`?token=${TOKEN}`); - }); - let rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options), preload: 10 }); - let rasterLayer2 = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(optionsMiniMap) }); - const overviewMapControl = new ol.control.OverviewMap({layers: [rasterLayer2], collapsed: false}); + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: layerName + }); + const optionsMiniMap = ol.source.WMTS.optionsFromCapabilities(results, { + layer: layerName + }); + options.urls = options.urls.map((url) => { + return url.concat(`?token=${TOKEN}`); + }); + optionsMiniMap.urls = optionsMiniMap.urls.map((url) => { + return url.concat(`?token=${TOKEN}`); + }); + let rasterLayer = new ol.layer.Tile({ + opacity: 1, + source: new ol.source.WMTS(options), + preload: 10 + }); + let rasterLayer2 = new ol.layer.Tile({ + opacity: 1, + source: new ol.source.WMTS(optionsMiniMap) + }); + const overviewMapControl = new ol.control.OverviewMap({ + layers: [rasterLayer2], + collapsed: false + }); - const map = new ol.Map({ - controls: ol.control.defaults.defaults().extend([overviewMapControl]), - target: 'map', - layers: [rasterLayer], - view: new ol.View({ - center: [34.465798, 31.513991], - zoom: 18, - projection: 'EPSG:4326', - minZoom: 1, - }), - }); - - }); + const map = new ol.Map({ + controls: ol.control.defaults.defaults().extend([overviewMapControl]), + target: 'map', + layers: [rasterLayer], + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + minZoom: 1 + }) + }); + }); diff --git a/examples/openlayers-permalink/permalink.css b/examples/openlayers-permalink/permalink.css index 1ff206f..3e6b562 100644 --- a/examples/openlayers-permalink/permalink.css +++ b/examples/openlayers-permalink/permalink.css @@ -1,7 +1,6 @@ -#map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; -} - \ No newline at end of file +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-permalink/permalink.html b/examples/openlayers-permalink/permalink.html index 2fdafd8..4fa1fbc 100644 --- a/examples/openlayers-permalink/permalink.html +++ b/examples/openlayers-permalink/permalink.html @@ -1,3 +1 @@ -
- -
\ No newline at end of file +
diff --git a/examples/openlayers-permalink/permalink.js b/examples/openlayers-permalink/permalink.js index 81730eb..bb2e0fc 100644 --- a/examples/openlayers-permalink/permalink.js +++ b/examples/openlayers-permalink/permalink.js @@ -8,80 +8,79 @@ let center = [0, 0]; let rotation = 0; if (window.location.hash !== '') { - // try to restore center, zoom-level and rotation from the URL - const hash = window.location.hash.replace('#map=', ''); - const parts = hash.split('/'); - if (parts.length === 4) { - zoom = parseFloat(parts[0]); - center = [parseFloat(parts[1]), parseFloat(parts[2])]; - rotation = parseFloat(parts[3]); - } + // try to restore center, zoom-level and rotation from the URL + const hash = window.location.hash.replace('#map=', ''); + const parts = hash.split('/'); + if (parts.length === 4) { + zoom = parseFloat(parts[0]); + center = [parseFloat(parts[1]), parseFloat(parts[2])]; + rotation = parseFloat(parts[3]); + } } const WMTSParser = new ol.format.WMTSCapabilities(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); const layer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); - const map = new ol.Map({ - target: 'map', - view: new ol.View({ - center: center, - zoom: zoom, - rotation: rotation, - projection: 'EPSG:4326', - }), - }); - map.addLayer(layer); - - let shouldUpdate = true; - const view = map.getView(); - const updatePermalink = function () { - if (!shouldUpdate) { - // do not update the URL when the view was changed in the 'popstate' handler - shouldUpdate = true; - return; - } + const map = new ol.Map({ + target: 'map', + view: new ol.View({ + center: center, + zoom: zoom, + rotation: rotation, + projection: 'EPSG:4326' + }) + }); + map.addLayer(layer); - const center = view.getCenter(); - const hash = - '#map=' + - view.getZoom().toFixed(2) + - '/' + - center[0].toFixed(2) + - '/' + - center[1].toFixed(2) + - '/' + - view.getRotation(); - const state = { - zoom: view.getZoom(), - center: view.getCenter(), - rotation: view.getRotation(), - }; - window.history.pushState(state, 'map', hash); - }; + let shouldUpdate = true; + const view = map.getView(); + const updatePermalink = function () { + if (!shouldUpdate) { + // do not update the URL when the view was changed in the 'popstate' handler + shouldUpdate = true; + return; + } - map.on('moveend', updatePermalink); + const center = view.getCenter(); + const hash = + '#map=' + + view.getZoom().toFixed(2) + + '/' + + center[0].toFixed(2) + + '/' + + center[1].toFixed(2) + + '/' + + view.getRotation(); + const state = { + zoom: view.getZoom(), + center: view.getCenter(), + rotation: view.getRotation() + }; + window.history.pushState(state, 'map', hash); + }; - // restore the view state when navigating through the history, see - // https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate - window.addEventListener('popstate', function (event) { - if (event.state === null) { - return; - } - map.getView().setCenter(event.state.center); - map.getView().setZoom(event.state.zoom); - map.getView().setRotation(event.state.rotation); - shouldUpdate = false; - }); + map.on('moveend', updatePermalink); - }); + // restore the view state when navigating through the history, see + // https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate + window.addEventListener('popstate', function (event) { + if (event.state === null) { + return; + } + map.getView().setCenter(event.state.center); + map.getView().setZoom(event.state.zoom); + map.getView().setRotation(event.state.rotation); + shouldUpdate = false; + }); + }); diff --git a/examples/openlayers-preload/preload.css b/examples/openlayers-preload/preload.css index 7a61158..acb63b6 100644 --- a/examples/openlayers-preload/preload.css +++ b/examples/openlayers-preload/preload.css @@ -1,6 +1,6 @@ -.map { - height: 50%; - top: 0; - bottom: 0; - width: 100%; -} +.map { + height: 50%; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-preload/preload.html b/examples/openlayers-preload/preload.html index c76a9d8..4aa8e68 100644 --- a/examples/openlayers-preload/preload.html +++ b/examples/openlayers-preload/preload.html @@ -1,2 +1,2 @@ -
-
+
+
diff --git a/examples/openlayers-preload/preload.js b/examples/openlayers-preload/preload.js index b1989ee..1db8d9e 100644 --- a/examples/openlayers-preload/preload.js +++ b/examples/openlayers-preload/preload.js @@ -5,33 +5,37 @@ import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); const sharedView = new ol.View({ - center: [0, 0], - zoom: 0, - projection: 'EPSG:4326', + center: [0, 0], + zoom: 0, + projection: 'EPSG:4326' }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); const layerNoPreload = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); - const layerPreload = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options), preload: 10 }); + const layerPreload = new ol.layer.Tile({ + opacity: 1, + source: new ol.source.WMTS(options), + preload: 10 + }); - const mapPreload = new ol.Map({ - target: 'map-preload', - layers: [layerPreload], - view: sharedView, - }); - const mapNoPreload = new ol.Map({ - target: 'map-no-preload', - layers: [layerNoPreload], - view: sharedView, - }); + const mapPreload = new ol.Map({ + target: 'map-preload', + layers: [layerPreload], + view: sharedView + }); + const mapNoPreload = new ol.Map({ + target: 'map-no-preload', + layers: [layerNoPreload], + view: sharedView + }); }); diff --git a/examples/openlayers-query-service/openlayers.css b/examples/openlayers-query-service/openlayers.css index dcac999..3e6b562 100644 --- a/examples/openlayers-query-service/openlayers.css +++ b/examples/openlayers-query-service/openlayers.css @@ -1,6 +1,6 @@ #map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; + position: absolute; + top: 0; + bottom: 0; + width: 100%; } diff --git a/examples/openlayers-query-service/query-service.js b/examples/openlayers-query-service/query-service.js index 2e40ac3..6ce02a4 100644 --- a/examples/openlayers-query-service/query-service.js +++ b/examples/openlayers-query-service/query-service.js @@ -8,48 +8,51 @@ const map = new ol.Map({ view: new ol.View({ center: [34.465798, 31.513991], zoom: 18, - projection: 'EPSG:4326', - }), + projection: 'EPSG:4326' + }) }); const WMTSParser = new ol.format.WMTSCapabilities(); let rasterLayer; - const vectorSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 512})), - url: function(extent) { - return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json&maxFeatures=10000`; - } - }); - - const vector = new ol.layer.Vector({ - source: vectorSource, - style: new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'rgba(255,0,0,0.5)', - width: 3 - }), - fill: new ol.style.Fill({ color: 'rgba(255,50,0,0.5)' }) - }), - minZoom: 15, - maxZoom: 20 - }); +const vectorSource = new ol.source.Vector({ + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({ tileSize: 512 })), + url: function (extent) { + return ( + VECTOR_WFS_URL + + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join( + ',' + )},EPSG:4326&token=${TOKEN}&outputFormat=application/json&maxFeatures=10000` + ); + } +}); +const vector = new ol.layer.Vector({ + source: vectorSource, + style: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'rgba(255,0,0,0.5)', + width: 3 + }), + fill: new ol.style.Fill({ color: 'rgba(255,50,0,0.5)' }) + }), + minZoom: 15, + maxZoom: 20 +}); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); map.addLayer(rasterLayer); - map.addLayer(vector); - + map.addLayer(vector); }); diff --git a/examples/openlayers-sensitive/interactive-sensitive.js b/examples/openlayers-sensitive/interactive-sensitive.js index ee0dad5..f8d0ddd 100644 --- a/examples/openlayers-sensitive/interactive-sensitive.js +++ b/examples/openlayers-sensitive/interactive-sensitive.js @@ -7,56 +7,62 @@ const WMTSParser = new ol.format.WMTSCapabilities(); let rasterLayer; const vectorSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 256})), - url: function(extent) { - return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json`; - } + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({ tileSize: 256 })), + url: function (extent) { + return ( + VECTOR_WFS_URL + + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:buildings_polygon&srsname=EPSG:4326&bbox=${extent.join( + ',' + )},EPSG:4326&token=${TOKEN}&outputFormat=application/json` + ); + } }); const style = new ol.style.Style({ - fill: new ol.style.Fill({ - color: '#eeeeee' - }), + fill: new ol.style.Fill({ + color: '#eeeeee' + }) }); const map = new ol.Map({ - target: 'map', - view: new ol.View({ - center: [34.465798, 31.513991], - zoom: 18, - projection: 'EPSG:4326', - constrainRotation: 16, - }), + target: 'map', + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + constrainRotation: 16 + }) }); const vectorLayer = new ol.layer.Vector({ - source: vectorSource, - style: function (feature) { - const color = feature.get('is_sensitive') === true ? 'rgba(255, 0, 0, 0.3)' : 'rgba(255, 255, 255, 0.7)'; - style.getFill().setColor(color); - return style; - }, - }) - + source: vectorSource, + style: function (feature) { + const color = + feature.get('is_sensitive') === true ? 'rgba(255, 0, 0, 0.3)' : 'rgba(255, 255, 255, 0.7)'; + style.getFill().setColor(color); + return style; + } +}); const selectedStyle = new ol.style.Style({ - fill: new ol.style.Fill({ - color: 'rgba(180, 2, 180, 0.3)', - }), - stroke: new ol.style.Stroke({ - color: 'rgba(180, 2, 180, 0.4)', - width: 10, - }), + fill: new ol.style.Fill({ + color: 'rgba(180, 2, 180, 0.3)' + }), + stroke: new ol.style.Stroke({ + color: 'rgba(180, 2, 180, 0.4)', + width: 10 + }) }); // a normal select interaction to handle click const select = new ol.interaction.Select({ - style: function (feature) { - const color = feature.get('is_sensitive') === true ? 'rgba(255, 0, 0, 1)' : 'rgba(255, 255, 255, 1)'; - selectedStyle.getFill().setColor(color); - return selectedStyle; - }, + style: function (feature) { + const color = + feature.get('is_sensitive') === true ? 'rgba(255, 0, 0, 1)' : 'rgba(255, 255, 255, 1)'; + selectedStyle.getFill().setColor(color); + return selectedStyle; + } }); map.addInteraction(select); @@ -65,30 +71,33 @@ const selectedFeatures = select.getFeatures(); const infoBox = document.getElementById('info'); selectedFeatures.on(['add', 'remove'], function () { - const names = selectedFeatures.getArray().map((feature) => { - return { 'סוג מבנה': feature.get('building_type'), GFID: feature.get('entity_id'), 'רגיש': feature.get('is_sensitive') }; - }); - console.clear(); - if (names.length > 0) { - infoBox.innerHTML = JSON.stringify(names, 2, 4); - } else { - infoBox.innerHTML = 'None'; - } + const names = selectedFeatures.getArray().map((feature) => { + return { + 'סוג מבנה': feature.get('building_type'), + GFID: feature.get('entity_id'), + רגיש: feature.get('is_sensitive') + }; + }); + console.clear(); + if (names.length > 0) { + infoBox.innerHTML = JSON.stringify(names, 2, 4); + } else { + infoBox.innerHTML = 'None'; + } }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); map.addLayer(rasterLayer); - map.addLayer(vectorLayer); - -}); + map.addLayer(vectorLayer); + }); diff --git a/examples/openlayers-sensitive/openlayers.css b/examples/openlayers-sensitive/openlayers.css index 46a9541..72b367f 100644 --- a/examples/openlayers-sensitive/openlayers.css +++ b/examples/openlayers-sensitive/openlayers.css @@ -1,6 +1,6 @@ #map { - top: 0; - bottom: 0; - height: 50%; - width: 100%; + top: 0; + bottom: 0; + height: 50%; + width: 100%; } diff --git a/examples/openlayers-sensitive/openlayers.html b/examples/openlayers-sensitive/openlayers.html index b6759df..e55b80c 100644 --- a/examples/openlayers-sensitive/openlayers.html +++ b/examples/openlayers-sensitive/openlayers.html @@ -1,8 +1,7 @@ -
-
-

Click on a sensitive feature (colored RED) to see details: - -

-
-
- +
+
+

+ Click on a sensitive feature (colored RED) to see details: + +

+
diff --git a/examples/openlayers-street-labels/street-labels.css b/examples/openlayers-street-labels/street-labels.css index 2af8466..3e6b562 100644 --- a/examples/openlayers-street-labels/street-labels.css +++ b/examples/openlayers-street-labels/street-labels.css @@ -1,7 +1,6 @@ -#map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; - } - \ No newline at end of file +#map { + position: absolute; + top: 0; + bottom: 0; + width: 100%; +} diff --git a/examples/openlayers-street-labels/street-labels.html b/examples/openlayers-street-labels/street-labels.html index b39cb78..ad19e7d 100644 --- a/examples/openlayers-street-labels/street-labels.html +++ b/examples/openlayers-street-labels/street-labels.html @@ -1 +1 @@ -
+
diff --git a/examples/openlayers-street-labels/street-labels.js b/examples/openlayers-street-labels/street-labels.js index 140a8a2..f5d4a94 100644 --- a/examples/openlayers-street-labels/street-labels.js +++ b/examples/openlayers-street-labels/street-labels.js @@ -5,68 +5,69 @@ import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); let rasterLayer; - const style = new ol.style.Style({ - text: new ol.style.Text({ - font: '20px "sans-serif"', - placement: 'line', - rotationWithView: true, - stroke: new ol.style.Stroke({ - color: 'white' - }), - fill: new ol.style.Fill({ - color: 'red', - }), - }), - stroke: new ol.style.Stroke({ - color: 'red' - }) + text: new ol.style.Text({ + font: '20px "sans-serif"', + placement: 'line', + rotationWithView: true, + stroke: new ol.style.Stroke({ + color: 'white' + }), + fill: new ol.style.Fill({ + color: 'red' + }) + }), + stroke: new ol.style.Stroke({ + color: 'red' + }) }); const vectorSource = new ol.source.Vector({ - format: new ol.format.GeoJSON(), - strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({tileSize: 256})), - url: function(extent) { - return VECTOR_WFS_URL + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:roads_line&srsname=EPSG:4326&bbox=${extent.join(',')},EPSG:4326&token=${TOKEN}&outputFormat=application/json&count=10000`; - } - }); + format: new ol.format.GeoJSON(), + strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({ tileSize: 256 })), + url: function (extent) { + return ( + VECTOR_WFS_URL + + `?service=WFS&version=2.0.0&request=GetFeature&typeName=core:roads_line&srsname=EPSG:4326&bbox=${extent.join( + ',' + )},EPSG:4326&token=${TOKEN}&outputFormat=application/json&count=10000` + ); + } +}); const vectorLayer = new ol.layer.Vector({ - declutter: true, - source: vectorSource, - style: function (feature) { - style.getText().setText(feature.get('name') === null ? 'לא ידוע' : feature.get('name')); - return style; - }, - minZoom: 15, - maxZoom: 20 - }); + declutter: true, + source: vectorSource, + style: function (feature) { + style.getText().setText(feature.get('name') === null ? 'לא ידוע' : feature.get('name')); + return style; + }, + minZoom: 15, + maxZoom: 20 +}); const map = new ol.Map({ - target: 'map', - view: new ol.View({ - center: [34.465798, 31.513991], - zoom: 18, - projection: 'EPSG:4326', - minZoom: 12, - }), + target: 'map', + view: new ol.View({ + center: [34.465798, 31.513991], + zoom: 18, + projection: 'EPSG:4326', + minZoom: 12 + }) }); - - fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { - const results = WMTSParser.read(text); - const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` - }); - options.urls = options.urls.map(url => { - return url.concat(`?token=${TOKEN}`); - }); - rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); - map.addLayer(rasterLayer); - map.addLayer(vectorLayer); - - }); + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { + const results = WMTSParser.read(text); + const options = ol.source.WMTS.optionsFromCapabilities(results, { + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + }); + options.urls = options.urls.map((url) => { + return url.concat(`?token=${TOKEN}`); + }); + rasterLayer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); + map.addLayer(rasterLayer); + map.addLayer(vectorLayer); + }); diff --git a/examples/openlayers-wmts/openlayers.css b/examples/openlayers-wmts/openlayers.css index dcac999..3e6b562 100644 --- a/examples/openlayers-wmts/openlayers.css +++ b/examples/openlayers-wmts/openlayers.css @@ -1,6 +1,6 @@ #map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; + position: absolute; + top: 0; + bottom: 0; + width: 100%; } diff --git a/examples/openlayers-wmts/wmts.js b/examples/openlayers-wmts/wmts.js index 1144b71..6bcc12a 100644 --- a/examples/openlayers-wmts/wmts.js +++ b/examples/openlayers-wmts/wmts.js @@ -9,19 +9,19 @@ const map = new ol.Map({ view: new ol.View({ center: [0, 0], zoom: 0, - projection: 'EPSG:4326', - }), + projection: 'EPSG:4326' + }) }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then(url => fetch(`${url}?token=${TOKEN}`)) - .then(response => response.text()) - .then(text => { + .then((url) => fetch(`${url}?token=${TOKEN}`)) + .then((response) => response.text()) + .then((text) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, + layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` }); - options.urls = options.urls.map(url => { + options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); }); const layer = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(options) }); diff --git a/examples/openlayers.css b/examples/openlayers.css index dcac999..3e6b562 100644 --- a/examples/openlayers.css +++ b/examples/openlayers.css @@ -1,6 +1,6 @@ #map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; + position: absolute; + top: 0; + bottom: 0; + width: 100%; } diff --git a/examples/openlayers_basic.js b/examples/openlayers_basic.js index 79f6836..7f75217 100644 --- a/examples/openlayers_basic.js +++ b/examples/openlayers_basic.js @@ -1,5 +1,5 @@ const map = new ol.Map({ - target: 'map', - layers: [new ol.layer.Tile({ source: new ol.source.OSM() })], - view: new ol.View({ center: [0, 0], zoom: 2 }), + target: 'map', + layers: [new ol.layer.Tile({ source: new ol.source.OSM() })], + view: new ol.View({ center: [0, 0], zoom: 2 }) }); diff --git a/examples/openlayers_geojson.js b/examples/openlayers_geojson.js index 3cc723e..b799445 100644 --- a/examples/openlayers_geojson.js +++ b/examples/openlayers_geojson.js @@ -1,241 +1,241 @@ const image = new ol.style.Circle({ - radius: 5, - fill: null, - stroke: new ol.style.Stroke({color: 'red', width: 1}), + radius: 5, + fill: null, + stroke: new ol.style.Stroke({ color: 'red', width: 1 }) }); const styles = { - 'Point': new ol.style.Style({ - image: image, - }), - 'LineString': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'green', - width: 1, - }), - }), - 'MultiLineString': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'green', - width: 1, - }), - }), - 'MultiPoint': new ol.style.Style({ - image: image, - }), - 'MultiPolygon': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'yellow', - width: 1, - }), - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 0, 0.1)', - }), - }), - 'Polygon': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'blue', - lineDash: [4], - width: 3, - }), - fill: new ol.style.Fill({ - color: 'rgba(0, 0, 255, 0.1)', - }), - }), - 'GeometryCollection': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'magenta', - width: 2, - }), - fill: new ol.style.Fill({ - color: 'magenta', - }), - image: new ol.style.Circle({ - radius: 10, - fill: null, - stroke: new ol.style.Stroke({ - color: 'magenta', - }), - }), - }), - 'Circle': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'red', - width: 2, - }), - fill: new ol.style.Fill({ - color: 'rgba(255,0,0,0.2)', - }), - }), + Point: new ol.style.Style({ + image: image + }), + LineString: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'green', + width: 1 + }) + }), + MultiLineString: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'green', + width: 1 + }) + }), + MultiPoint: new ol.style.Style({ + image: image + }), + MultiPolygon: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'yellow', + width: 1 + }), + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 0, 0.1)' + }) + }), + Polygon: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'blue', + lineDash: [4], + width: 3 + }), + fill: new ol.style.Fill({ + color: 'rgba(0, 0, 255, 0.1)' + }) + }), + GeometryCollection: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'magenta', + width: 2 + }), + fill: new ol.style.Fill({ + color: 'magenta' + }), + image: new ol.style.Circle({ + radius: 10, + fill: null, + stroke: new ol.style.Stroke({ + color: 'magenta' + }) + }) + }), + Circle: new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: 'red', + width: 2 + }), + fill: new ol.style.Fill({ + color: 'rgba(255,0,0,0.2)' + }) + }) }; const styleFunction = function (feature) { - return styles[feature.getGeometry().getType()]; + return styles[feature.getGeometry().getType()]; }; const geojsonObject = { - 'type': 'FeatureCollection', - 'crs': { - 'type': 'name', - 'properties': { - 'name': 'EPSG:3857', - }, - }, - 'features': [ - { - 'type': 'Feature', - 'geometry': { - 'type': 'Point', - 'coordinates': [0, 0], - }, - }, - { - 'type': 'Feature', - 'geometry': { - 'type': 'LineString', - 'coordinates': [ - [4e6, -2e6], - [8e6, 2e6], - ], - }, - }, - { - 'type': 'Feature', - 'geometry': { - 'type': 'LineString', - 'coordinates': [ - [4e6, 2e6], - [8e6, -2e6], - ], - }, - }, - { - 'type': 'Feature', - 'geometry': { - 'type': 'Polygon', - 'coordinates': [ - [ - [-5e6, -1e6], - [-3e6, -1e6], - [-4e6, 1e6], - [-5e6, -1e6], - ], - ], - }, - }, - { - 'type': 'Feature', - 'geometry': { - 'type': 'MultiLineString', - 'coordinates': [ - [ - [-1e6, -7.5e5], - [-1e6, 7.5e5], - ], - [ - [1e6, -7.5e5], - [1e6, 7.5e5], - ], - [ - [-7.5e5, -1e6], - [7.5e5, -1e6], - ], - [ - [-7.5e5, 1e6], - [7.5e5, 1e6], - ], - ], - }, - }, - { - 'type': 'Feature', - 'geometry': { - 'type': 'MultiPolygon', - 'coordinates': [ - [ - [ - [-5e6, 6e6], - [-3e6, 6e6], - [-3e6, 8e6], - [-5e6, 8e6], - [-5e6, 6e6], - ], - ], - [ - [ - [-2e6, 6e6], - [0, 6e6], - [0, 8e6], - [-2e6, 8e6], - [-2e6, 6e6], - ], - ], - [ - [ - [1e6, 6e6], - [3e6, 6e6], - [3e6, 8e6], - [1e6, 8e6], - [1e6, 6e6], - ], - ], - ], - }, - }, - { - 'type': 'Feature', - 'geometry': { - 'type': 'GeometryCollection', - 'geometries': [ - { - 'type': 'LineString', - 'coordinates': [ - [-5e6, -5e6], - [0, -5e6], - ], - }, - { - 'type': 'Point', - 'coordinates': [4e6, -5e6], - }, - { - 'type': 'Polygon', - 'coordinates': [ - [ - [1e6, -6e6], - [3e6, -6e6], - [2e6, -4e6], - [1e6, -6e6], - ], - ], - }, - ], - }, - }, - ], + type: 'FeatureCollection', + crs: { + type: 'name', + properties: { + name: 'EPSG:3857' + } + }, + features: [ + { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [0, 0] + } + }, + { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [ + [4e6, -2e6], + [8e6, 2e6] + ] + } + }, + { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [ + [4e6, 2e6], + [8e6, -2e6] + ] + } + }, + { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [-5e6, -1e6], + [-3e6, -1e6], + [-4e6, 1e6], + [-5e6, -1e6] + ] + ] + } + }, + { + type: 'Feature', + geometry: { + type: 'MultiLineString', + coordinates: [ + [ + [-1e6, -7.5e5], + [-1e6, 7.5e5] + ], + [ + [1e6, -7.5e5], + [1e6, 7.5e5] + ], + [ + [-7.5e5, -1e6], + [7.5e5, -1e6] + ], + [ + [-7.5e5, 1e6], + [7.5e5, 1e6] + ] + ] + } + }, + { + type: 'Feature', + geometry: { + type: 'MultiPolygon', + coordinates: [ + [ + [ + [-5e6, 6e6], + [-3e6, 6e6], + [-3e6, 8e6], + [-5e6, 8e6], + [-5e6, 6e6] + ] + ], + [ + [ + [-2e6, 6e6], + [0, 6e6], + [0, 8e6], + [-2e6, 8e6], + [-2e6, 6e6] + ] + ], + [ + [ + [1e6, 6e6], + [3e6, 6e6], + [3e6, 8e6], + [1e6, 8e6], + [1e6, 6e6] + ] + ] + ] + } + }, + { + type: 'Feature', + geometry: { + type: 'GeometryCollection', + geometries: [ + { + type: 'LineString', + coordinates: [ + [-5e6, -5e6], + [0, -5e6] + ] + }, + { + type: 'Point', + coordinates: [4e6, -5e6] + }, + { + type: 'Polygon', + coordinates: [ + [ + [1e6, -6e6], + [3e6, -6e6], + [2e6, -4e6], + [1e6, -6e6] + ] + ] + } + ] + } + } + ] }; const vectorSource = new ol.source.Vector({ - features: new ol.format.GeoJSON().readFeatures(geojsonObject), + features: new ol.format.GeoJSON().readFeatures(geojsonObject) }); vectorSource.addFeature(new ol.Feature(new ol.geom.Circle([5e6, 7e6], 1e6))); const vectorLayer = new ol.layer.Vector({ - source: vectorSource, - style: styleFunction, + source: vectorSource, + style: styleFunction }); const map = new ol.Map({ - layers: [ - new ol.layer.Tile({ - source: new ol.source.OSM(), - }), - vectorLayer, - ], - target: 'map', - view: new ol.View({ - center: [0, 0], - zoom: 2, - }), + layers: [ + new ol.layer.Tile({ + source: new ol.source.OSM() + }), + vectorLayer + ], + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 2 + }) }); diff --git a/examples/utils/catalog-client.js b/examples/utils/catalog-client.js index 7bc4751..b4c66ff 100644 --- a/examples/utils/catalog-client.js +++ b/examples/utils/catalog-client.js @@ -2,15 +2,15 @@ import { MAPCOLONIES_CATALOG_URL, TOKEN } from './config/common-config.js'; import { parseXml } from './utils/xml-utils.js'; const TYPENAMES = { - raster: 'mc:MCRasterRecord', - '3d': 'mc:MC3DRecord', - dem: 'mc:MCDEMRecord', + raster: 'mc:MCRasterRecord', + '3d': 'mc:MC3DRecord', + dem: 'mc:MCDEMRecord' }; const namespaceFor = (catalogKey) => `http://schema.mapcolonies.com/${catalogKey}`; function buildGetRecordsBody(typename, namespace, productId, productType) { - return ` + return ` full @@ -33,36 +33,38 @@ function buildGetRecordsBody(typename, namespace, productId, productType) { } function parseLinks(xmlText, namespace) { - const doc = parseXml(xmlText, 'CSW response'); - return Array.from(doc.getElementsByTagNameNS(namespace, 'links')).reduce((acc, node) => { - const scheme = node.getAttribute('scheme'); - if (scheme) acc[scheme] = (node.textContent || '').trim(); - return acc; - }, {}); + const doc = parseXml(xmlText, 'CSW response'); + return Array.from(doc.getElementsByTagNameNS(namespace, 'links')).reduce((acc, node) => { + const scheme = node.getAttribute('scheme'); + if (scheme) acc[scheme] = (node.textContent || '').trim(); + return acc; + }, {}); } export async function fetchRecordLinks(catalogKey, productId, productType) { - const typename = TYPENAMES[catalogKey]; - if (!typename) throw new Error(`Unknown catalog: ${catalogKey}`); - const namespace = namespaceFor(catalogKey); - const res = await fetch(`${MAPCOLONIES_CATALOG_URL}/api/${catalogKey}/v1/csw`, { - method: 'POST', - headers: { 'Content-Type': 'application/xml', 'x-api-key': TOKEN }, - body: buildGetRecordsBody(typename, namespace, productId, productType), - }); - if (!res.ok) { - throw new Error(`CSW ${catalogKey} ${productId} failed: ${res.status}`); - } - return parseLinks(await res.text(), namespace); + const typename = TYPENAMES[catalogKey]; + if (!typename) throw new Error(`Unknown catalog: ${catalogKey}`); + const namespace = namespaceFor(catalogKey); + const res = await fetch(`${MAPCOLONIES_CATALOG_URL}/api/${catalogKey}/v1/csw`, { + method: 'POST', + headers: { 'Content-Type': 'application/xml', 'x-api-key': TOKEN }, + body: buildGetRecordsBody(typename, namespace, productId, productType) + }); + if (!res.ok) { + throw new Error(`CSW ${catalogKey} ${productId} failed: ${res.status}`); + } + return parseLinks(await res.text(), namespace); } export async function fetchServiceLink(catalogKey, productId, productType, scheme) { - const links = await fetchRecordLinks(catalogKey, productId, productType); - const url = links[scheme]; - if (!url) { - throw new Error( - `No "${scheme}" link in ${catalogKey}/${productId}. Available: ${Object.keys(links).join(', ')}` - ); - } - return url; + const links = await fetchRecordLinks(catalogKey, productId, productType); + const url = links[scheme]; + if (!url) { + throw new Error( + `No "${scheme}" link in ${catalogKey}/${productId}. Available: ${Object.keys(links).join( + ', ' + )}` + ); + } + return url; } diff --git a/examples/utils/wmts-utils.js b/examples/utils/wmts-utils.js index eed5237..2143966 100644 --- a/examples/utils/wmts-utils.js +++ b/examples/utils/wmts-utils.js @@ -7,29 +7,30 @@ const WMTS_NS = 'http://www.opengis.net/wmts/1.0'; const OWS_NS = 'http://www.opengis.net/ows/1.1'; export function extractWmtsTileTemplate(capabilitiesXml, layerName, format) { - const doc = parseXml(capabilitiesXml, 'WMTS capabilities'); - const layer = Array.from(doc.getElementsByTagNameNS(WMTS_NS, 'Layer')).find(node => { - const identifier = node.getElementsByTagNameNS(OWS_NS, 'Identifier')[0]; - return identifier && identifier.textContent.trim() === layerName; - }); - if (!layer) { - throw new Error(`Layer "${layerName}" not found in WMTS capabilities`); - } - const resourceUrl = Array.from(layer.getElementsByTagNameNS(WMTS_NS, 'ResourceURL')).find(node => - node.getAttribute('resourceType') === 'tile' && - (!format || node.getAttribute('format') === format) - ); - if (!resourceUrl) { - throw new Error(`No tile ResourceURL for layer "${layerName}"`); - } - return resourceUrl.getAttribute('template'); + const doc = parseXml(capabilitiesXml, 'WMTS capabilities'); + const layer = Array.from(doc.getElementsByTagNameNS(WMTS_NS, 'Layer')).find((node) => { + const identifier = node.getElementsByTagNameNS(OWS_NS, 'Identifier')[0]; + return identifier && identifier.textContent.trim() === layerName; + }); + if (!layer) { + throw new Error(`Layer "${layerName}" not found in WMTS capabilities`); + } + const resourceUrl = Array.from(layer.getElementsByTagNameNS(WMTS_NS, 'ResourceURL')).find( + (node) => + node.getAttribute('resourceType') === 'tile' && + (!format || node.getAttribute('format') === format) + ); + if (!resourceUrl) { + throw new Error(`No tile ResourceURL for layer "${layerName}"`); + } + return resourceUrl.getAttribute('template'); } export async function fetchWmtsTileTemplate(productId, productType, format) { - const capabilitiesUrl = await fetchServiceLink('raster', productId, productType, RASTER_SCHEME); - const res = await fetch(`${capabilitiesUrl}?token=${TOKEN}`); - if (!res.ok) { - throw new Error(`Fetching WMTS capabilities failed: ${res.status}`); - } - return extractWmtsTileTemplate(await res.text(), `${productId}-${productType}`, format); + const capabilitiesUrl = await fetchServiceLink('raster', productId, productType, RASTER_SCHEME); + const res = await fetch(`${capabilitiesUrl}?token=${TOKEN}`); + if (!res.ok) { + throw new Error(`Fetching WMTS capabilities failed: ${res.status}`); + } + return extractWmtsTileTemplate(await res.text(), `${productId}-${productType}`, format); } diff --git a/examples/utils/xml-utils.js b/examples/utils/xml-utils.js index 09330af..159ab6c 100644 --- a/examples/utils/xml-utils.js +++ b/examples/utils/xml-utils.js @@ -1,8 +1,8 @@ export function parseXml(xmlText, context) { - const doc = new DOMParser().parseFromString(xmlText, 'application/xml'); - const parseError = doc.getElementsByTagName('parsererror')[0]; - if (parseError) { - throw new Error(`${context} parse error: ${parseError.textContent}`); - } - return doc; + const doc = new DOMParser().parseFromString(xmlText, 'application/xml'); + const parseError = doc.getElementsByTagName('parsererror')[0]; + if (parseError) { + throw new Error(`${context} parse error: ${parseError.textContent}`); + } + return doc; } diff --git a/src/app.html b/src/app.html index 992f774..569c80e 100644 --- a/src/app.html +++ b/src/app.html @@ -7,11 +7,7 @@ %sveltekit.head% - +
%sveltekit.body%
diff --git a/src/lib/components/bottomBar.svelte b/src/lib/components/bottomBar.svelte index 1343a49..3ceec36 100644 --- a/src/lib/components/bottomBar.svelte +++ b/src/lib/components/bottomBar.svelte @@ -23,7 +23,7 @@ diff --git a/src/lib/components/bottomHeaderItem.svelte b/src/lib/components/bottomHeaderItem.svelte index ed3d78d..9167e93 100644 --- a/src/lib/components/bottomHeaderItem.svelte +++ b/src/lib/components/bottomHeaderItem.svelte @@ -1,15 +1,15 @@ - \ No newline at end of file + diff --git a/src/lib/components/flems.svelte b/src/lib/components/flems.svelte index 1947165..4a68d3c 100644 --- a/src/lib/components/flems.svelte +++ b/src/lib/components/flems.svelte @@ -12,7 +12,6 @@ autoHeight: false }; - let flemsInstance: any; $: if (flemsInstance) { diff --git a/src/lib/server/s3wrapper.ts b/src/lib/server/s3wrapper.ts index 57843bb..3e327bc 100644 --- a/src/lib/server/s3wrapper.ts +++ b/src/lib/server/s3wrapper.ts @@ -23,14 +23,13 @@ const client = new S3Client({ secretAccessKey }, forcePathStyle: true, - region: awsRegion ?? 'us-east-1', + region: awsRegion ?? 'us-east-1' }); export async function getStringObject(key: string): Promise { const command = new GetObjectCommand({ Bucket: bucket, - Key: key, - + Key: key }); const res = await client.send(command); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index cd4c8a1..f12d0d7 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -20,7 +20,7 @@ Map Puzzle
- +
diff --git a/src/routes/demo/+layout.server.ts b/src/routes/demo/+layout.server.ts index 85c9dbf..a3ba560 100644 --- a/src/routes/demo/+layout.server.ts +++ b/src/routes/demo/+layout.server.ts @@ -33,11 +33,11 @@ export async function load({ params }): Promise { const index = await getDemoIndex(); if (client === undefined || index[client] === undefined) { - throw error(404, `no client named ${client} found.`) + throw error(404, `no client named ${client} found.`); } if (demoName === undefined || index[client][demoName] === undefined) { - throw error(404, `no demo named ${demoName} found in client ${client} found.`) + throw error(404, `no demo named ${demoName} found in client ${client} found.`); } return memoized(index, client); diff --git a/src/routes/files/+page.svelte b/src/routes/files/+page.svelte index c3ec906..c8dc0ae 100644 --- a/src/routes/files/+page.svelte +++ b/src/routes/files/+page.svelte @@ -1,31 +1,40 @@ - - File Name - File Local Path - Relative App Path - - Link - - - - {#each data.files as file} - - {file.name} - {file.path} - {file.urlPath} - - - Link - - - - {/each} - -
\ No newline at end of file + + File Name + File Local Path + Relative App Path + + Link + + + + {#each data.files as file} + + {file.name} + {file.path} + {file.urlPath} + + + Link + + + + {/each} + + From 1c07c2e92b335165680ae37bbc9e32e423d2c2e0 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Fri, 5 Jun 2026 17:52:58 +0300 Subject: [PATCH 11/21] chore: add comments to explain the helper functions --- examples/utils/catalog-client.js | 37 ++++++++++++++++++++++++++++++++ examples/utils/wmts-utils.js | 27 +++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/examples/utils/catalog-client.js b/examples/utils/catalog-client.js index b4c66ff..da9fe7a 100644 --- a/examples/utils/catalog-client.js +++ b/examples/utils/catalog-client.js @@ -9,6 +9,15 @@ const TYPENAMES = { const namespaceFor = (catalogKey) => `http://schema.mapcolonies.com/${catalogKey}`; +/** + * Builds a CSW 2.0.2 GetRecords XML body that filters by productId and productType. + * + * @param {string} typename - CSW typeName for the catalog (e.g. 'mc:MCRasterRecord'). + * @param {string} namespace - XML namespace URI for the catalog schema. + * @param {string} productId - Product identifier to match (e.g. 'blueMarble'). + * @param {string} productType - Product type to match (e.g. 'Orthophoto'). + * @returns {string} CSW GetRecords request XML. + */ function buildGetRecordsBody(typename, namespace, productId, productType) { return ` @@ -32,8 +41,16 @@ function buildGetRecordsBody(typename, namespace, productId, productType) { `; } +/** + * Parses a CSW response and collects every `` element into a scheme → URL map. + * + * @param {string} xmlText - Raw CSW response XML. + * @param {string} namespace - Namespace URI used for `` elements in the response. + * @returns {Record} Map of scheme name (e.g. 'WMTS', 'WCS', '3DTiles') to service URL. + */ function parseLinks(xmlText, namespace) { const doc = parseXml(xmlText, 'CSW response'); + // Each node carries a `scheme` attribute and the service URL as text content. return Array.from(doc.getElementsByTagNameNS(namespace, 'links')).reduce((acc, node) => { const scheme = node.getAttribute('scheme'); if (scheme) acc[scheme] = (node.textContent || '').trim(); @@ -41,6 +58,15 @@ function parseLinks(xmlText, namespace) { }, {}); } +/** + * Queries a MapColonies CSW catalog for a single record and returns it's link map. + * + * @param {'raster'|'3d'|'dem'} catalogKey - Which catalog to query. + * @param {string} productId - Product identifier to look up. + * @param {string} productType - Product type to look up. + * @returns {Promise>} Map of scheme → service URL exposed by the record. + * @throws If the catalog key is unknown or the CSW request fails. + */ export async function fetchRecordLinks(catalogKey, productId, productType) { const typename = TYPENAMES[catalogKey]; if (!typename) throw new Error(`Unknown catalog: ${catalogKey}`); @@ -56,6 +82,17 @@ export async function fetchRecordLinks(catalogKey, productId, productType) { return parseLinks(await res.text(), namespace); } +/** + * Resolves the service URL for a specific scheme on a catalog record. + * Thin convenience wrapper around `fetchRecordLinks` for the common single-scheme lookup. + * + * @param {'raster'|'3d'|'dem'} catalogKey - Catalog the product lives in. + * @param {string} productId - Product identifier. + * @param {string} productType - Product type. + * @param {string} scheme - Scheme name to pick from the record (e.g. 'WMTS', 'WCS', '3DTiles'). + * @returns {Promise} Service URL for the requested scheme. + * @throws If the requested scheme is not advertised by the record; the error lists the schemes that are. + */ export async function fetchServiceLink(catalogKey, productId, productType, scheme) { const links = await fetchRecordLinks(catalogKey, productId, productType); const url = links[scheme]; diff --git a/examples/utils/wmts-utils.js b/examples/utils/wmts-utils.js index 2143966..5a18c4b 100644 --- a/examples/utils/wmts-utils.js +++ b/examples/utils/wmts-utils.js @@ -6,8 +6,21 @@ import { parseXml } from './utils/xml-utils.js'; const WMTS_NS = 'http://www.opengis.net/wmts/1.0'; const OWS_NS = 'http://www.opengis.net/ows/1.1'; +/** + * Extracts the RESTful tile URL template for a specific layer from a WMTS capabilities document. + * + * The returned template contains WMTS placeholders ({TileMatrix}, {TileRow}, {TileCol}, ...) + * that the caller is expected to substitute when requesting tiles. + * + * @param {string} capabilitiesXml - Raw WMTS capabilities XML. + * @param {string} layerName - `` of the layer to look up. + * @param {string} [format] - Optional MIME type to require on the ResourceURL (e.g. 'image/png'). + * @returns {string} The tile URL template. + * @throws If the layer is not present, or no matching tile ResourceURL is found. + */ export function extractWmtsTileTemplate(capabilitiesXml, layerName, format) { const doc = parseXml(capabilitiesXml, 'WMTS capabilities'); + // Locate the whose matches the requested layerName. const layer = Array.from(doc.getElementsByTagNameNS(WMTS_NS, 'Layer')).find((node) => { const identifier = node.getElementsByTagNameNS(OWS_NS, 'Identifier')[0]; return identifier && identifier.textContent.trim() === layerName; @@ -15,6 +28,7 @@ export function extractWmtsTileTemplate(capabilitiesXml, layerName, format) { if (!layer) { throw new Error(`Layer "${layerName}" not found in WMTS capabilities`); } + // Pick the tile ResourceURL, optionally constrained to the requested format. const resourceUrl = Array.from(layer.getElementsByTagNameNS(WMTS_NS, 'ResourceURL')).find( (node) => node.getAttribute('resourceType') === 'tile' && @@ -26,8 +40,21 @@ export function extractWmtsTileTemplate(capabilitiesXml, layerName, format) { return resourceUrl.getAttribute('template'); } +/** + * Resolves the raster catalog entry for a product, fetches its WMTS capabilities, + * and returns the tile URL template for the `${productId}-${productType}` layer. + * + * Convenience helper that wraps the full catalog → capabilities → template chain. + * + * @param {string} productId - Raster product identifier. + * @param {string} productType - Raster product type. + * @param {string} [format] - Optional MIME type filter passed to `extractWmtsTileTemplate`. + * @returns {Promise} Tile URL template (still contains WMTS placeholders). + * @throws If the catalog lookup, capabilities fetch, or layer extraction fails. + */ export async function fetchWmtsTileTemplate(productId, productType, format) { const capabilitiesUrl = await fetchServiceLink('raster', productId, productType, RASTER_SCHEME); + // Capabilities endpoint is token-gated; same token is later used per-tile by the caller. const res = await fetch(`${capabilitiesUrl}?token=${TOKEN}`); if (!res.ok) { throw new Error(`Fetching WMTS capabilities failed: ${res.status}`); From f16704614dc528f162bb4e60d14c07c5b1cc77f9 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Fri, 5 Jun 2026 18:00:21 +0300 Subject: [PATCH 12/21] chore: remove unused file --- examples/markdown.md | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 examples/markdown.md diff --git a/examples/markdown.md b/examples/markdown.md deleted file mode 100644 index bce741b..0000000 --- a/examples/markdown.md +++ /dev/null @@ -1,31 +0,0 @@ -# Heading level 1 - -## Heading level 2 - -### Heading level 3 - -# Heading level 1 - -1. First item -2. Second item -3. Third item -4. Fourth item - -At the command prompt, type `nano`. - - - - -```javascript -function test() { - console.log('notice the blank line before this function?'); -} -``` - -```mermaid -graph TD; - A-->B; - A-->C; - B-->D; - C-->D; -``` From fff1f4a35f1b01ac303406a85222d64f573f8025 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 7 Jun 2026 17:21:33 +0300 Subject: [PATCH 13/21] style: ignore assets and run prettier --- .prettierignore | 2 ++ release-please-config.json | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.prettierignore b/.prettierignore index d715da5..14109c7 100644 --- a/.prettierignore +++ b/.prettierignore @@ -12,3 +12,5 @@ static pnpm-lock.yaml package-lock.json yarn.lock + +examples/assets/ diff --git a/release-please-config.json b/release-please-config.json index e1b178b..f310b21 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -1,8 +1,8 @@ { - "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", - "release-type": "node", - "include-component-in-tag": false, - "packages": { - ".": {} - } + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "node", + "include-component-in-tag": false, + "packages": { + ".": {} + } } From ace20f25f307821f2242c3355b4f3b3f07dd473a Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 7 Jun 2026 17:24:10 +0300 Subject: [PATCH 14/21] build: update package lock --- package-lock.json | 685 +++++++++------------------------------------- 1 file changed, 128 insertions(+), 557 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53fcf39..91e0588 100644 --- a/package-lock.json +++ b/package-lock.json @@ -404,16 +404,16 @@ } }, "node_modules/@aws-sdk/checksums": { - "version": "3.1000.1", - "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.1.tgz", - "integrity": "sha512-DFCtlisEuWzw7rESV65jHK7De1QsJZRZgUNJ8ovpmdVaayPrxvmlsAlW8hka9E7f9B31d1T7lHG9oozZf6Bp6w==", + "version": "3.1000.2", + "resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.2.tgz", + "integrity": "sha512-PIha+kauTbp6IRmOpYktPTrlfrrSqDVixvhO/EUOFOf62DPX81CaJoHJreuA1m9HYpSKyXf99BKjU1dvJPeUfw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", "@aws-crypto/crc32c": "5.2.0", "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -423,24 +423,20 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.1061.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1061.0.tgz", - "integrity": "sha512-ygyRCIkktaDz4/kNzsxhbZqocLwCJV5absi/k7Xd3LThPOmVkid7Nghm/xTW2Yg+vSQIL0yq99oV7u3T+4ZbAQ==", + "version": "3.1063.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1063.0.tgz", + "integrity": "sha512-ETn+vvmZVK1MmOZwVBXmWANpmD5iTbzojIqyEIoZ86qo+8oWy35S8QyQNE/ZDI+WHgMU1dS+VSYbpRl1QkEySg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/credential-provider-node": "^3.972.50", - "@aws-sdk/middleware-bucket-endpoint": "^3.972.20", - "@aws-sdk/middleware-expect-continue": "^3.972.16", - "@aws-sdk/middleware-flexible-checksums": "^3.974.26", - "@aws-sdk/middleware-location-constraint": "^3.972.13", - "@aws-sdk/middleware-sdk-s3": "^3.972.47", - "@aws-sdk/middleware-ssec": "^3.972.13", - "@aws-sdk/signature-v4-multi-region": "^3.996.31", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/credential-provider-node": "^3.972.52", + "@aws-sdk/middleware-flexible-checksums": "^3.974.27", + "@aws-sdk/middleware-sdk-s3": "^3.972.48", + "@aws-sdk/signature-v4-multi-region": "^3.996.32", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", @@ -452,13 +448,13 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.974.17", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.17.tgz", - "integrity": "sha512-r8o4h2K7j6P9ngno+8ei0aK0U/4JwDb7A2fMMxGVoSqDN8AFlIzSDeZHME9LcVLR2codyhtr1WAAg+/nmkeeMA==", + "version": "3.974.18", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.18.tgz", + "integrity": "sha512-JDYCPI0j7zGrzXTDFsLB346cxss7J/AxH7+O0MzWlqppJBEyB9Qe6TQXRL6iwLUo/xZkNv9KFmBL2hqElmwW0g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.10", - "@aws-sdk/xml-builder": "^3.972.27", + "@aws-sdk/types": "^3.973.11", + "@aws-sdk/xml-builder": "^3.972.28", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.6", "@smithy/signature-v4": "^5.4.6", @@ -471,13 +467,13 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.43", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.43.tgz", - "integrity": "sha512-g0XVQKzaA/4cq1vz1IvCQwYM+1Pkv01J9yHDpCTXekVuGZRDEz0wqBQ1AuYTq7FM6uik4uBGH8Tb5d9YvgeA7g==", + "version": "3.972.44", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.44.tgz", + "integrity": "sha512-3hKJVrZ7bqXzDAXCQp+OaQ1ASN+vWstaNuEH418wQVl//cRZhqhfR9Bjk1qIWmgUGe8/D3gdO73PgidRj378EQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -487,13 +483,13 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.45", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.45.tgz", - "integrity": "sha512-w9PuOoKCt6+xoESvY+zlV0u3PKQ0mVL259PcsVR6a3S/uYJJHnIi4r1NxdJHEcNldUVRIciltWnFMGBR4YEm3g==", + "version": "3.972.46", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.46.tgz", + "integrity": "sha512-VhwC9pGAZHhiQ2xSViyOPDFqvr9aRxGCAXZtADsUhU3R65nad7y//CwynE6mQnWNR+suRlqE79W36IVayL+m1g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", @@ -505,20 +501,20 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.48", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.48.tgz", - "integrity": "sha512-+6BQ6Lrnc+EyAGElLRW6j+Sa+RirPHnIJsobvYO6nnyK+oGKmz1ne/ieclbLWyjyDKEU3/JVJWcWY3VLFPvGtQ==", + "version": "3.972.50", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.50.tgz", + "integrity": "sha512-09Xi6ovxiK42+De/qBGF71sT5F2bWgYM+1fFyDwSOpy1xpsQ5R/naIu7MVDpH6Dic36QNc8dAv4KADtMGK2JYg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/credential-provider-env": "^3.972.43", - "@aws-sdk/credential-provider-http": "^3.972.45", - "@aws-sdk/credential-provider-login": "^3.972.47", - "@aws-sdk/credential-provider-process": "^3.972.43", - "@aws-sdk/credential-provider-sso": "^3.972.47", - "@aws-sdk/credential-provider-web-identity": "^3.972.47", - "@aws-sdk/nested-clients": "^3.997.15", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/credential-provider-env": "^3.972.44", + "@aws-sdk/credential-provider-http": "^3.972.46", + "@aws-sdk/credential-provider-login": "^3.972.49", + "@aws-sdk/credential-provider-process": "^3.972.44", + "@aws-sdk/credential-provider-sso": "^3.972.49", + "@aws-sdk/credential-provider-web-identity": "^3.972.49", + "@aws-sdk/nested-clients": "^3.997.17", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", "@smithy/types": "^4.14.3", @@ -529,14 +525,14 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.47", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.47.tgz", - "integrity": "sha512-Iy2ebWVgrZBH05464uJiQYu6HSSiROnwVZptthEFXx2gWjo1ORCxEAFZB5Cr2MdfrSnZ+0QUPkZ1ZpCqpkUrLQ==", + "version": "3.972.49", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.49.tgz", + "integrity": "sha512-EfJF/1Fh9mI4pZyoheU2RY9xUhTcugIZNkD63+orXMkYj/QXacJNbKVDUK90Yv5hE+aX+rt9J/EZ9Qr3vKOa7g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/nested-clients": "^3.997.15", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/nested-clients": "^3.997.17", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -546,18 +542,18 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.50", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.50.tgz", - "integrity": "sha512-b05Aelq5cqAvCCDQjCYacl0XmR8QhBNSqLbsdISkQmlQBa5oPS66zYPteWcSp5LswbpoIe552EUGjluKiadBig==", + "version": "3.972.52", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.52.tgz", + "integrity": "sha512-7QX+PbyiWBEOVipJq8Nke/TqXT6lAPLE7fvTaopa39/IVWuLfS+Fzdy71sZJONf/mLGgmtj6aU17+REw3+aRrw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.43", - "@aws-sdk/credential-provider-http": "^3.972.45", - "@aws-sdk/credential-provider-ini": "^3.972.48", - "@aws-sdk/credential-provider-process": "^3.972.43", - "@aws-sdk/credential-provider-sso": "^3.972.47", - "@aws-sdk/credential-provider-web-identity": "^3.972.47", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/credential-provider-env": "^3.972.44", + "@aws-sdk/credential-provider-http": "^3.972.46", + "@aws-sdk/credential-provider-ini": "^3.972.50", + "@aws-sdk/credential-provider-process": "^3.972.44", + "@aws-sdk/credential-provider-sso": "^3.972.49", + "@aws-sdk/credential-provider-web-identity": "^3.972.49", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/credential-provider-imds": "^4.3.7", "@smithy/types": "^4.14.3", @@ -568,13 +564,13 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.43", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.43.tgz", - "integrity": "sha512-GPokLNyvTfCmuaHk+v3GKVs4ZT3cMu5kgS2a+NPkOMt96cq6fSIK0g+mZHpGS6Cd4QGrPKesANEaLUKgOskTzg==", + "version": "3.972.44", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.44.tgz", + "integrity": "sha512-V+UUhZpRP7QDRhi+qgBDisM9tUBnYmMje8Bk77A6MZsfeGeGdMsQXmaHP1CDYFcept0o/Rz5g2Y0TMeVlG9dzg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -584,15 +580,15 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.47", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.47.tgz", - "integrity": "sha512-0AzvLrzlvJs0DzbeWGvNj+bX3Uzd7VNS6vDqCOdZzBlCGKGd78uxctJSW9iK/Rt/nxiJqpTvrYQlVJ4guVM2Dw==", + "version": "3.972.49", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.49.tgz", + "integrity": "sha512-9QqOYGuh5tZ76OzaT68kwI78AH+5lS/uZGGvkfxb3fc8FzRrIz2jOufNTliEBEeSAwmgK2rWLNsK+IB3zbtNPA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/nested-clients": "^3.997.15", - "@aws-sdk/token-providers": "3.1060.0", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/nested-clients": "^3.997.17", + "@aws-sdk/token-providers": "3.1063.0", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -602,14 +598,14 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.47", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.47.tgz", - "integrity": "sha512-eksfbUErOejUAGWBAcNqaP7IX21oUOEo73d9R56k9Ua4d57qS90NEYkWJsuSGzTXMFulCu17qXJI/qGmM7hvoA==", + "version": "3.972.49", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.49.tgz", + "integrity": "sha512-IYx1lN38MnnPXv+NBLpuATu0cZakbZ321TAfjW+aVkw7HIJF38YnEwdeEO55MSl3pl7hIX1IvvnD6EmnAzmAJw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/nested-clients": "^3.997.15", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/nested-clients": "^3.997.17", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -618,52 +614,13 @@ "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.972.20", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.20.tgz", - "integrity": "sha512-D35MfedGvTTzK1oygFPjm7DViSJwj9cuPV26ElHKwZqEz2rWag1hzYeAQ7st0jlCIAAihQgOyQ0/JwmqLOOinw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-sdk-s3": "^3.972.47", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.972.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.16.tgz", - "integrity": "sha512-S52iw+M9zJC+7uxRdvvKeiR0s2PDeYEmbNZQkWE6OJf8upIs+r4WQY0TER+6akVitEMeRdwS0DrBUhKkmpsyng==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-sdk-s3": "^3.972.47", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.974.26", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.26.tgz", - "integrity": "sha512-WndRXQV8wAU/bW3GH8THumEOSV7FpS0AtoluT2M7lYaaDUyG0gOCD+DppB+IWQ4TPmzuTtFcCedh9xCzM4Zv4g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/checksums": "^3.1000.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.13.tgz", - "integrity": "sha512-Yh0MmpADMsSR7ExRM/2w85D26i/U2aDC/pC7fMwhUpmOl6sebGpmBPoRL/uJRDhqRrwX/tvXWWZrsbsPM/O9FQ==", + "version": "3.974.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.27.tgz", + "integrity": "sha512-bZqezPLdllFC4VAeV/f+EIc/hz56ab3TD/+4zNCgOgmG5ZHAE5dMHrX1gtTwdcQXbPr3KR7x3zTC3zuCTE6+ng==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "^3.972.47", + "@aws-sdk/checksums": "^3.1000.2", "tslib": "^2.6.2" }, "engines": { @@ -671,14 +628,14 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.972.47", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.47.tgz", - "integrity": "sha512-fzVBvGib8P1G6RFV3qVTPlXy9bMFAy5nxhdhA7LwyhWjRkJufNfJIPiloZq2mt36YAXSlLsEa4s3Kgcw6cv3+g==", + "version": "3.972.48", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.48.tgz", + "integrity": "sha512-MRTqx8wD/T3REt6LTT3/yN8rrp6+xIHrbUekkDYJTYWVch70mwtdJBovR4qKJz1jIPlbN+9R/Sn6R04BfsglzA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/signature-v4-multi-region": "^3.996.31", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/signature-v4-multi-region": "^3.996.32", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -687,30 +644,17 @@ "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.13.tgz", - "integrity": "sha512-M+dDhWp2zv9u92I4/4rgUFdiF8jSIk5PIj5ktyBdhvR/dkmKSYMo07nuh+3g8/59HnizwkcRC3glcLMX5GhyaQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-sdk-s3": "^3.972.47", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.15", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.15.tgz", - "integrity": "sha512-Fpri1/PXKMKveORZ7E00VLTlWS5DkfZkW70PUE+bOnpWpAeHAQLoiDHhkzN3kNWbbSsGg64+IZYiq/EZgME3Mg==", + "version": "3.997.17", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.17.tgz", + "integrity": "sha512-lDRgraoTfKRawUyc176Ow93mrNrOho/x+EoK4C+lKU+vKkHWhNhzvSMVAx0WEJUJoeQxxDN5ZdKMfiGEyNejig==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/signature-v4-multi-region": "^3.996.31", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/signature-v4-multi-region": "^3.996.32", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/fetch-http-handler": "^5.4.6", "@smithy/node-http-handler": "^4.7.6", @@ -722,12 +666,12 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.31", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.31.tgz", - "integrity": "sha512-Kn2up9SlG1KC6wRtwf0d7waTGF6rvp9DxYqB54x6UCKdQ6kyaXCqHL4WGb5vUJga5kS8FxnjhY0LqM28aMvnNQ==", + "version": "3.996.32", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.32.tgz", + "integrity": "sha512-llvApLcsWtmRFhG2wT3WIp1CmDeRaIYutqty1ZZXoMzK7TiJ6MOLOimk9eXUS8PwgG4ew4pa4QAbt0lfhn++1w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/types": "^3.973.11", "@smithy/signature-v4": "^5.4.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -737,14 +681,14 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.1060.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1060.0.tgz", - "integrity": "sha512-6NZaMKkFhpaNiwLpHi1sZaYjidL/lCJE6ME6NxwA8gv9vQna+Kr0j4OFwVoz6tANRWM3WbGz6jiPsGX/Vkjwow==", + "version": "3.1063.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1063.0.tgz", + "integrity": "sha512-nYDaWWdzjKiDP5xj8k4oUgcYd4WPgzfAOgdU5vJsaqH/07Dfvm7ffisHCFJ+NEl7kUC9JEIUxh0kznvenbo3NQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.17", - "@aws-sdk/nested-clients": "^3.997.15", - "@aws-sdk/types": "^3.973.10", + "@aws-sdk/core": "^3.974.18", + "@aws-sdk/nested-clients": "^3.997.17", + "@aws-sdk/types": "^3.973.11", "@smithy/core": "^3.24.6", "@smithy/types": "^4.14.3", "tslib": "^2.6.2" @@ -754,9 +698,9 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.973.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.10.tgz", - "integrity": "sha512-992QrTO7G9qCvKD0fx1rMlqcL14plUcRAbwmqqYVsuF3GrqcvlAL9qxR+baMafarEZ+l7DUQ5lCMmt5mbMhF7g==", + "version": "3.973.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.11.tgz", + "integrity": "sha512-YjS0qFuECClRh4qhEyW8XagW0fwEPBeZ1cfsW/gU73Kh/ExFILxbzxOfPCmzF/2DwEvhvsHYt0b0qnvStwKYrg==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.3", @@ -767,9 +711,9 @@ } }, "node_modules/@aws-sdk/util-locate-window": { - "version": "3.965.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", - "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", + "version": "3.965.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.6.tgz", + "integrity": "sha512-ZfHjfwSzeXj+Lg9AK5ZNmeDkXev6V+w2tn1t4kgDdRtUaRCthepTQiFwbD06EF9oNGH4LaLg+Mb6U16Ypv5bSw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -779,9 +723,9 @@ } }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.27", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.27.tgz", - "integrity": "sha512-hpsCXCOI436kxWpjtRuIHVvuPP81MOw8f18jzfZeg+UOiiOvlqWcmWChzEhJEu16cOC6+ku4ncBN+7rdt+DZ9g==", + "version": "3.972.28", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.28.tgz", + "integrity": "sha512-lI/l3c/vPvsxmspzV63NfS3x9q4CkMmdhJy4QiM+NThAufVkDvi/PZZQ6xETnICL0UD7jI808pY83gllf86RFg==", "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.14.3", @@ -1263,367 +1207,10 @@ "node": ">=12" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -2236,9 +1823,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", - "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "version": "20.19.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.42.tgz", + "integrity": "sha512-5L7SUaFC1RyDraj2yRhyBzHTobyXHmohD100CChNtyPyleoq37Mqab5Gn8XEKI04dfN/oqPdpHk38MgcQWHbZg==", "dev": true, "license": "MIT", "dependencies": { @@ -2706,9 +2293,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.33", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", - "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "version": "2.10.34", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz", + "integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2833,9 +2420,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001793", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", - "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "version": "1.0.30001797", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz", + "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==", "dev": true, "funding": [ { @@ -3132,9 +2719,9 @@ "license": "ISC" }, "node_modules/electron-to-chromium": { - "version": "1.5.367", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.367.tgz", - "integrity": "sha512-4Mk/mrynCNQ+atY40D3UpmhLWB6AHMbYMlIrPhHcMF6x0L7O0b052FCAsxw1LlaR++UFuNg3D/A6XCuGDa0guQ==", + "version": "1.5.368", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz", + "integrity": "sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==", "dev": true, "license": "ISC" }, @@ -3854,21 +3441,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5071,11 +4643,10 @@ } }, "node_modules/protobufjs": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.5.0.tgz", - "integrity": "sha512-df1jWDPA5VIBNRtuAHjqr09f2qN5D4Vke1wYqOQg1XJ7ZDpA7BD6L7E4tyChgGRLB5hqk2m79Zsy0WHwV9a84A==", + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.6.1.tgz", + "integrity": "sha512-s4qQPr4pU0W95iYnUInh95skjIg+3aM2sakYsw60QYanU+qWRDY2zQxOAQV6zU7ROJpSNDG9B+VSmk4dqdWWSA==", "dev": true, - "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { "long": "^5.3.2" From d105a10131f08be9a8c77b2825ac7d6c44414698 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Sun, 7 Jun 2026 17:49:14 +0300 Subject: [PATCH 15/21] fix: build issue --- src/lib/server/s3wrapper.ts | 58 +++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/lib/server/s3wrapper.ts b/src/lib/server/s3wrapper.ts index 257ad40..cdf908b 100644 --- a/src/lib/server/s3wrapper.ts +++ b/src/lib/server/s3wrapper.ts @@ -1,32 +1,46 @@ import { env } from '$env/dynamic/private'; import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3'; -const { - AWS_ACCESS_KEY_ID: accessKeyId, - AWS_SECRET_ACCESS_KEY: secretAccessKey, - AWS_ENDPOINT_URL: awsEndpointUrl, - AWS_REGION: awsRegion, - AWS_BUCKET: bucket, - INDEX_KEY: indexKey -} = env; - -for (const item of [accessKeyId, secretAccessKey, awsEndpointUrl, bucket, indexKey]) { - if (item === undefined) { - throw new Error(`env: ${item} is undefined`); +let cachedClient: S3Client | undefined; +let cachedBucket: string | undefined; + +function getClient(): { client: S3Client; bucket: string } { + if (cachedClient && cachedBucket) { + return { client: cachedClient, bucket: cachedBucket }; + } + + const { + AWS_ACCESS_KEY_ID: accessKeyId, + AWS_SECRET_ACCESS_KEY: secretAccessKey, + AWS_ENDPOINT_URL: awsEndpointUrl, + AWS_REGION: awsRegion, + AWS_BUCKET: bucket, + INDEX_KEY: indexKey + } = env; + + const required = { accessKeyId, secretAccessKey, awsEndpointUrl, bucket, indexKey }; + for (const [name, value] of Object.entries(required)) { + if (value === undefined) { + throw new Error(`env: ${name} is undefined`); + } } -} -const client = new S3Client({ - endpoint: awsEndpointUrl, - credentials: { - accessKeyId: accessKeyId as string, - secretAccessKey: secretAccessKey as string - }, - forcePathStyle: true, - region: awsRegion ?? 'us-east-1' -}); + cachedClient = new S3Client({ + endpoint: awsEndpointUrl, + credentials: { + accessKeyId: accessKeyId as string, + secretAccessKey: secretAccessKey as string + }, + forcePathStyle: true, + region: awsRegion ?? 'us-east-1' + }); + cachedBucket = bucket; + + return { client: cachedClient, bucket: cachedBucket as string }; +} export async function getStringObject(key: string): Promise { + const { client, bucket } = getClient(); const command = new GetObjectCommand({ Bucket: bucket, Key: key From 050b63894fb6e5319f4ac15a4f58770cd4147c91 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 9 Jun 2026 08:46:46 +0300 Subject: [PATCH 16/21] chore: remove irrelevant data --- examples/config/common-config.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/config/common-config.js b/examples/config/common-config.js index 2dd43a0..3f60bf9 100644 --- a/examples/config/common-config.js +++ b/examples/config/common-config.js @@ -1,6 +1,5 @@ -export var MAPCOLONIES_TILES_URL = 'https://tiles.mapcolonies.net'; -export var MAPCOLONIES_QUERY_URL = 'https://query.mapcolonies.net'; -export var MAPCOLONIES_GEOCODING_URL = 'https://geocoding.mapcolonies.net'; -export var MAPCOLONIES_CATALOG_URL = 'https://catalog.mapcolonies.net'; -export var TOKEN = - 'eyJhbGciOiJSUzI1NiIsImtpZCI6Im1hcC1jb2xvbmllcy1pbnQifQ.eyJkIjpbInJhc3RlciIsInZlY3RvciIsIjNkIiwiZGVtIl0sImlhdCI6MTcxMTU2MDY0NSwic3ViIjoiYmFyYWsiLCJpc3MiOiJtYXBjb2xvbmllcy10b2tlbi1jbGkifQ.qupSnHv9H1N9A9iKS5CCNO7A6LKipR3TpFYz_ViV2iqKWIIv3pUlQ_SFESubZiL-TuRFBaxzC8HqUmzV1Q0F3M209QzSOhPyzGme-oFQncqfJstKm_ji8Q6weR9RkZVzfssRed1C6FY1D4bHH-q8qLBKnorU_S0aYbHMwawHLTAmKoDBPetADLT64doxLy5kCpgL0dPQLdXQKIlLqw1whXsk_x4UG1BYtD-Zb0lxJ_FkaZWWfU5cpgFgDQo7gI2q0oUlxZPqCmpiKhq3njWZWmDv-G8S8XcNNeml94dVjHnqFbc_DKxHLXV2QuIS3koPUTHdyctaHtxaCEKW0XHOfA'; +export var MAPCOLONIES_TILES_URL = 'TILES_URL'; +export var MAPCOLONIES_QUERY_URL = 'QUERY_URL'; +export var MAPCOLONIES_GEOCODING_URL = 'GEOCODING_URL'; +export var MAPCOLONIES_CATALOG_URL = 'CATALOG_URL'; +export var TOKEN = 'TOKEN'; From 6048e719c12259af65c48ce4c2f9d549e467f157 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 9 Jun 2026 08:47:35 +0300 Subject: [PATCH 17/21] style: run prettier --- README.md | 110 +++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 15364ca..97fa2a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # MapColonies Playground + Code playground for mapping clients. The code examples are saved in S3 bucket and fetched and cached by the server. @@ -21,62 +22,63 @@ The code examples are saved in S3 bucket and fetched and cached by the server. The codes examples shown are defined by a json index file with all the data needed. All the files listed in the index are loaded from the same bucket as the index itself. ### example index + ```json { - "ol": { - "basic-ol": { - "displayName": "basic openlayers", - "files": ["openlayers_basic.js", "openlayers.css", "openlayers.html"], - "links": [ - { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, - { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } - ] - }, - "geojson-style-ol": { - "displayName": "geojson openlayers", - "files": ["openlayers_geojson.js", "openlayers.css", "openlayers.html"], - "links": [ - { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, - { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } - ] - } - }, - "cesium": { - "basic-cesium": { - "displayName": "basic cesium", - "files": ["cesium_basic.js", "cesium.html"], - "links": [ - { - "name": "cesium.js", - "url": "/libs/Cesium/Cesium.js", - "type": "js" - }, - { - "name": "widgets.css", - "url": "/libs/Cesium/Widgets/widgets.css", - "type": "css" - } - ] - } - }, - "leaflet": { - "basic-leaflet": { - "displayName": "basic leaflet", - "files": ["leaflet_basic.js", "leaflet.css", "leaflet.html"], - "links": [ - { - "name": "leaflet.js", - "url": "/libs/leaflet/1.9.4/leaflet.js", - "type": "js" - }, - { - "name": "leaflet.css", - "url": "/libs/leaflet/1.9.4/leaflet.css", - "type": "css" - } - ] - } - } + "ol": { + "basic-ol": { + "displayName": "basic openlayers", + "files": ["openlayers_basic.js", "openlayers.css", "openlayers.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + }, + "geojson-style-ol": { + "displayName": "geojson openlayers", + "files": ["openlayers_geojson.js", "openlayers.css", "openlayers.html"], + "links": [ + { "name": "ol.css", "url": "/libs/ol/v7.3.0/ol.css", "type": "css" }, + { "name": "ol.js", "url": "/libs/ol/v7.3.0/ol.js", "type": "js" } + ] + } + }, + "cesium": { + "basic-cesium": { + "displayName": "basic cesium", + "files": ["cesium_basic.js", "cesium.html"], + "links": [ + { + "name": "cesium.js", + "url": "/libs/Cesium/Cesium.js", + "type": "js" + }, + { + "name": "widgets.css", + "url": "/libs/Cesium/Widgets/widgets.css", + "type": "css" + } + ] + } + }, + "leaflet": { + "basic-leaflet": { + "displayName": "basic leaflet", + "files": ["leaflet_basic.js", "leaflet.css", "leaflet.html"], + "links": [ + { + "name": "leaflet.js", + "url": "/libs/leaflet/1.9.4/leaflet.js", + "type": "js" + }, + { + "name": "leaflet.css", + "url": "/libs/leaflet/1.9.4/leaflet.css", + "type": "css" + } + ] + } + } } ``` From ab98bc1e12bf251ff8c45992ca10bbbc35cb9121 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Tue, 9 Jun 2026 20:35:05 +0300 Subject: [PATCH 18/21] refactor: use layer name returned from catalog --- examples/cesium-3d/3d-model.js | 10 +-- examples/cesium-geocoding/cesium.js | 6 +- examples/cesium-layers-split/split-layers.js | 10 +-- examples/cesium-terrain/cesium.js | 14 ++-- examples/cesium-viewshed/viewshed.js | 10 +-- examples/cesium-wmts/cesium.js | 6 +- examples/leaflet-wmts/wmts.js | 7 +- examples/ol-ext-example/ol-ext.js | 11 ++-- .../openlayers-box-selection/box-selection.js | 11 ++-- .../openlayers-debug-layer/debug-layer.js | 11 ++-- .../draw-and-modify.js | 11 ++-- .../openlayers-overview-map/overview-map.js | 14 ++-- examples/openlayers-permalink/permalink.js | 11 ++-- examples/openlayers-preload/preload.js | 11 ++-- .../openlayers-query-service/query-service.js | 11 ++-- .../interactive-sensitive.js | 11 ++-- .../openlayers-street-labels/street-labels.js | 11 ++-- examples/openlayers-wmts/wmts.js | 11 ++-- examples/utils/catalog-client.js | 64 +++++++------------ examples/utils/wmts-utils.js | 14 ++-- 20 files changed, 143 insertions(+), 122 deletions(-) diff --git a/examples/cesium-3d/3d-model.js b/examples/cesium-3d/3d-model.js index c859321..ce69dd5 100644 --- a/examples/cesium-3d/3d-model.js +++ b/examples/cesium-3d/3d-model.js @@ -21,16 +21,16 @@ Promise.all([ fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, DEM_SCHEME), fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME) -]).then(([tileTemplate, demUrl, modelUrl]) => { +]).then(([raster, dem, model]) => { const viewer = new Cesium.Viewer('cesiumContainer', { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: tileTemplate, + url: raster.template, queryParameters: { token: TOKEN } }), - layer: `${RASTER_PRODUCT_ID}-${RASTER_PRODUCT_TYPE}`, + layer: raster.name, style: 'default', format: LAYER_IMAGE_FORMAT, tileMatrixSetID: 'WorldCRS84', @@ -38,7 +38,7 @@ Promise.all([ }), terrainProvider: new Cesium.CesiumTerrainProvider({ url: new Cesium.Resource({ - url: demUrl, + url: dem.url, queryParameters: { token: TOKEN } @@ -49,7 +49,7 @@ Promise.all([ viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: new Cesium.Resource({ - url: modelUrl, + url: model.url, queryParameters: { token: TOKEN } diff --git a/examples/cesium-geocoding/cesium.js b/examples/cesium-geocoding/cesium.js index c887471..b824f49 100644 --- a/examples/cesium-geocoding/cesium.js +++ b/examples/cesium-geocoding/cesium.js @@ -36,7 +36,7 @@ OpenStreetMapNominatimGeocoder.prototype.geocode = function (input) { }); }; -fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then((tileTemplate) => { +fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then(({ template, name }) => { new Cesium.Viewer('cesiumContainer', { vrButton: false, homeButton: false, @@ -46,12 +46,12 @@ fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then((tileTe shouldAnimate: false, imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: tileTemplate, + url: template, queryParameters: { token: TOKEN } }), - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, + layer: name, style: 'default', format: LAYER_IMAGE_FORMAT, tileMatrixSetID: 'WorldCRS84', diff --git a/examples/cesium-layers-split/split-layers.js b/examples/cesium-layers-split/split-layers.js index b147d69..2015443 100644 --- a/examples/cesium-layers-split/split-layers.js +++ b/examples/cesium-layers-split/split-layers.js @@ -6,16 +6,16 @@ import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; Promise.all([ fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT), fetchWmtsTileTemplate('OSM', 'RasterVectorBest', LAYER_IMAGE_FORMAT) -]).then(([mainTemplate, secondTemplate]) => { +]).then(([main, second]) => { const viewer = new Cesium.Viewer('cesiumContainer', { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: mainTemplate, + url: main.template, queryParameters: { token: TOKEN } }), - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, + layer: main.name, style: 'default', format: LAYER_IMAGE_FORMAT, tileMatrixSetID: 'WorldCRS84', @@ -29,12 +29,12 @@ Promise.all([ const secondLayer = layers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: secondTemplate, + url: second.template, queryParameters: { token: TOKEN } }), - layer: 'OSM-RasterVectorBest', + layer: second.name, style: 'default', format: LAYER_IMAGE_FORMAT, tileMatrixSetID: 'WorldCRS84', diff --git a/examples/cesium-terrain/cesium.js b/examples/cesium-terrain/cesium.js index 45d80f0..b2fb41e 100644 --- a/examples/cesium-terrain/cesium.js +++ b/examples/cesium-terrain/cesium.js @@ -15,16 +15,16 @@ import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; Promise.all([ fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, DEM_SCHEME) -]).then(([tileTemplate, demUrl]) => { +]).then(([raster, dem]) => { const viewer = new Cesium.Viewer('cesiumContainer', { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: tileTemplate, + url: raster.template, queryParameters: { token: TOKEN } }), - layer: `${RASTER_PRODUCT_ID}-${RASTER_PRODUCT_TYPE}`, + layer: raster.name, style: 'default', format: LAYER_IMAGE_FORMAT, tileMatrixSetID: 'newGrids', @@ -32,7 +32,7 @@ Promise.all([ }), terrainProvider: new Cesium.CesiumTerrainProvider({ url: new Cesium.Resource({ - url: demUrl, + url: dem.url, queryParameters: { token: TOKEN } @@ -50,16 +50,16 @@ Promise.all([ }); fetchWmtsTileTemplate('WORLD_MAP_BASE_THIN', 'RasterVectorBest', 'image/png').then( - (secondTemplate) => { + ({ template, name }) => { viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: secondTemplate, + url: template, queryParameters: { token: TOKEN } }), - layer: 'WORLD_MAP_BASE_THIN-RasterVectorBest', + layer: name, style: 'default', format: 'image/png', tileMatrixSetID: 'newGrids', diff --git a/examples/cesium-viewshed/viewshed.js b/examples/cesium-viewshed/viewshed.js index 428ae26..177e8ec 100644 --- a/examples/cesium-viewshed/viewshed.js +++ b/examples/cesium-viewshed/viewshed.js @@ -574,16 +574,16 @@ Promise.all([ fetchWmtsTileTemplate(RASTER_PRODUCT_ID, RASTER_PRODUCT_TYPE, LAYER_IMAGE_FORMAT), fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, DEM_SCHEME), fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME) -]).then(([tileTemplate, demUrl, modelUrl]) => { +]).then(([raster, dem, model]) => { viewer = new Cesium.Viewer('cesiumContainer', { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: tileTemplate, + url: raster.template, queryParameters: { token: TOKEN } }), - layer: `${RASTER_PRODUCT_ID}-${RASTER_PRODUCT_TYPE}`, + layer: raster.name, style: 'default', format: LAYER_IMAGE_FORMAT, tileMatrixSetID: 'WorldCRS84', @@ -591,7 +591,7 @@ Promise.all([ }), terrainProvider: new Cesium.CesiumTerrainProvider({ url: new Cesium.Resource({ - url: demUrl, + url: dem.url, queryParameters: { token: TOKEN } @@ -602,7 +602,7 @@ Promise.all([ viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: new Cesium.Resource({ - url: modelUrl, + url: model.url, queryParameters: { token: TOKEN } diff --git a/examples/cesium-wmts/cesium.js b/examples/cesium-wmts/cesium.js index eafdb17..bb4f7ff 100644 --- a/examples/cesium-wmts/cesium.js +++ b/examples/cesium-wmts/cesium.js @@ -2,16 +2,16 @@ import { TOKEN } from './config/common-config.js'; import { PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; -fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then((tileTemplate) => { +fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then(({ template, name }) => { new Cesium.Viewer('cesiumContainer', { imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: new Cesium.Resource({ - url: tileTemplate, + url: template, queryParameters: { token: TOKEN } }), - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}`, + layer: name, style: 'default', format: LAYER_IMAGE_FORMAT, tileMatrixSetID: 'WorldCRS84', diff --git a/examples/leaflet-wmts/wmts.js b/examples/leaflet-wmts/wmts.js index e8bb088..180cbe3 100644 --- a/examples/leaflet-wmts/wmts.js +++ b/examples/leaflet-wmts/wmts.js @@ -10,11 +10,10 @@ const parser = (urlTemplate) => { .replace('{TileCol}', '{x}'); }; -const layerName = `${PRODUCT_ID}-${PRODUCT_TYPE}`; const map = L.map('map', { crs: L.CRS.EPSG4326 }).setView([0.0, 0.0], 1); -fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE).then((urlTemplate) => { - const parsedUrl = parser(urlTemplate); - const layer = L.tileLayer(parsedUrl + `?token=${TOKEN}`, { id: layerName }); +fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE).then(({ template, name }) => { + const parsedUrl = parser(template); + const layer = L.tileLayer(parsedUrl + `?token=${TOKEN}`, { id: name }); map.addLayer(layer); }); diff --git a/examples/ol-ext-example/ol-ext.js b/examples/ol-ext-example/ol-ext.js index 97978d0..153ddbb 100644 --- a/examples/ol-ext-example/ol-ext.js +++ b/examples/ol-ext-example/ol-ext.js @@ -14,12 +14,15 @@ const map = new ol.Map({ const WMTSParser = new ol.format.WMTSCapabilities(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-box-selection/box-selection.js b/examples/openlayers-box-selection/box-selection.js index 1d84d73..10f3896 100644 --- a/examples/openlayers-box-selection/box-selection.js +++ b/examples/openlayers-box-selection/box-selection.js @@ -150,12 +150,15 @@ selectedFeatures.on(['add', 'remove'], function () { }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-debug-layer/debug-layer.js b/examples/openlayers-debug-layer/debug-layer.js index 9811b59..b55af11 100644 --- a/examples/openlayers-debug-layer/debug-layer.js +++ b/examples/openlayers-debug-layer/debug-layer.js @@ -14,12 +14,15 @@ const map = new ol.Map({ const WMTSParser = new ol.format.WMTSCapabilities(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-draw-and-modify/draw-and-modify.js b/examples/openlayers-draw-and-modify/draw-and-modify.js index 59a6712..512d8cc 100644 --- a/examples/openlayers-draw-and-modify/draw-and-modify.js +++ b/examples/openlayers-draw-and-modify/draw-and-modify.js @@ -170,12 +170,15 @@ typeSelect.onchange = function () { addInteractions(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-overview-map/overview-map.js b/examples/openlayers-overview-map/overview-map.js index 6956ca0..d6a579c 100644 --- a/examples/openlayers-overview-map/overview-map.js +++ b/examples/openlayers-overview-map/overview-map.js @@ -3,18 +3,20 @@ import { PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME } from './config/raster-config. import { fetchServiceLink } from './utils/catalog-client.js'; const WMTSParser = new ol.format.WMTSCapabilities(); -const layerName = `${PRODUCT_ID}-${PRODUCT_TYPE}`; fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: layerName + layer: name }); const optionsMiniMap = ol.source.WMTS.optionsFromCapabilities(results, { - layer: layerName + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-permalink/permalink.js b/examples/openlayers-permalink/permalink.js index bb2e0fc..4467d41 100644 --- a/examples/openlayers-permalink/permalink.js +++ b/examples/openlayers-permalink/permalink.js @@ -21,12 +21,15 @@ if (window.location.hash !== '') { const WMTSParser = new ol.format.WMTSCapabilities(); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-preload/preload.js b/examples/openlayers-preload/preload.js index 1db8d9e..2aec33a 100644 --- a/examples/openlayers-preload/preload.js +++ b/examples/openlayers-preload/preload.js @@ -11,12 +11,15 @@ const sharedView = new ol.View({ }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-query-service/query-service.js b/examples/openlayers-query-service/query-service.js index 6ce02a4..68d603a 100644 --- a/examples/openlayers-query-service/query-service.js +++ b/examples/openlayers-query-service/query-service.js @@ -42,12 +42,15 @@ const vector = new ol.layer.Vector({ }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-sensitive/interactive-sensitive.js b/examples/openlayers-sensitive/interactive-sensitive.js index f8d0ddd..8e7a86e 100644 --- a/examples/openlayers-sensitive/interactive-sensitive.js +++ b/examples/openlayers-sensitive/interactive-sensitive.js @@ -87,12 +87,15 @@ selectedFeatures.on(['add', 'remove'], function () { }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-street-labels/street-labels.js b/examples/openlayers-street-labels/street-labels.js index f5d4a94..f408044 100644 --- a/examples/openlayers-street-labels/street-labels.js +++ b/examples/openlayers-street-labels/street-labels.js @@ -57,12 +57,15 @@ const map = new ol.Map({ }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/openlayers-wmts/wmts.js b/examples/openlayers-wmts/wmts.js index 6bcc12a..7214905 100644 --- a/examples/openlayers-wmts/wmts.js +++ b/examples/openlayers-wmts/wmts.js @@ -14,12 +14,15 @@ const map = new ol.Map({ }); fetchServiceLink('raster', PRODUCT_ID, PRODUCT_TYPE, RASTER_SCHEME) - .then((url) => fetch(`${url}?token=${TOKEN}`)) - .then((response) => response.text()) - .then((text) => { + .then(({ url, name }) => + fetch(`${url}?token=${TOKEN}`) + .then((response) => response.text()) + .then((text) => ({ text, name })) + ) + .then(({ text, name }) => { const results = WMTSParser.read(text); const options = ol.source.WMTS.optionsFromCapabilities(results, { - layer: `${PRODUCT_ID}-${PRODUCT_TYPE}` + layer: name }); options.urls = options.urls.map((url) => { return url.concat(`?token=${TOKEN}`); diff --git a/examples/utils/catalog-client.js b/examples/utils/catalog-client.js index da9fe7a..34c3c8e 100644 --- a/examples/utils/catalog-client.js +++ b/examples/utils/catalog-client.js @@ -42,32 +42,36 @@ function buildGetRecordsBody(typename, namespace, productId, productType) { } /** - * Parses a CSW response and collects every `` element into a scheme → URL map. + * Parses a CSW response and returns the service URL and layer name for the requested scheme. * * @param {string} xmlText - Raw CSW response XML. * @param {string} namespace - Namespace URI used for `` elements in the response. - * @returns {Record} Map of scheme name (e.g. 'WMTS', 'WCS', '3DTiles') to service URL. + * @param {string} scheme - Scheme name to pick (e.g. 'WMTS', 'WCS', '3DTiles'). + * @returns {{ url: string, name: string } | null} Service URL and layer name from the `name` attribute, or null if no matching `` element is present. */ -function parseLinks(xmlText, namespace) { +function parseLink(xmlText, namespace, scheme) { const doc = parseXml(xmlText, 'CSW response'); - // Each node carries a `scheme` attribute and the service URL as text content. - return Array.from(doc.getElementsByTagNameNS(namespace, 'links')).reduce((acc, node) => { - const scheme = node.getAttribute('scheme'); - if (scheme) acc[scheme] = (node.textContent || '').trim(); - return acc; - }, {}); + const node = Array.from(doc.getElementsByTagNameNS(namespace, 'links')).find( + (n) => n.getAttribute('scheme') === scheme + ); + if (!node) return null; + return { + url: (node.textContent || '').trim(), + name: node.getAttribute('name') || '' + }; } /** - * Queries a MapColonies CSW catalog for a single record and returns it's link map. + * Resolves the service URL and layer name for a specific scheme on a catalog record. * - * @param {'raster'|'3d'|'dem'} catalogKey - Which catalog to query. - * @param {string} productId - Product identifier to look up. - * @param {string} productType - Product type to look up. - * @returns {Promise>} Map of scheme → service URL exposed by the record. - * @throws If the catalog key is unknown or the CSW request fails. + * @param {'raster'|'3d'|'dem'} catalogKey - Catalog the product lives in. + * @param {string} productId - Product identifier. + * @param {string} productType - Product type. + * @param {string} scheme - Scheme name to pick from the record (e.g. 'WMTS', 'WCS', '3DTiles'). + * @returns {Promise<{ url: string, name: string }>} Service URL and layer name from the matched `` element. + * @throws If the catalog key is unknown, the CSW request fails, or the scheme is not advertised. */ -export async function fetchRecordLinks(catalogKey, productId, productType) { +export async function fetchServiceLink(catalogKey, productId, productType, scheme) { const typename = TYPENAMES[catalogKey]; if (!typename) throw new Error(`Unknown catalog: ${catalogKey}`); const namespace = namespaceFor(catalogKey); @@ -79,29 +83,9 @@ export async function fetchRecordLinks(catalogKey, productId, productType) { if (!res.ok) { throw new Error(`CSW ${catalogKey} ${productId} failed: ${res.status}`); } - return parseLinks(await res.text(), namespace); -} - -/** - * Resolves the service URL for a specific scheme on a catalog record. - * Thin convenience wrapper around `fetchRecordLinks` for the common single-scheme lookup. - * - * @param {'raster'|'3d'|'dem'} catalogKey - Catalog the product lives in. - * @param {string} productId - Product identifier. - * @param {string} productType - Product type. - * @param {string} scheme - Scheme name to pick from the record (e.g. 'WMTS', 'WCS', '3DTiles'). - * @returns {Promise} Service URL for the requested scheme. - * @throws If the requested scheme is not advertised by the record; the error lists the schemes that are. - */ -export async function fetchServiceLink(catalogKey, productId, productType, scheme) { - const links = await fetchRecordLinks(catalogKey, productId, productType); - const url = links[scheme]; - if (!url) { - throw new Error( - `No "${scheme}" link in ${catalogKey}/${productId}. Available: ${Object.keys(links).join( - ', ' - )}` - ); + const link = parseLink(await res.text(), namespace, scheme); + if (!link) { + throw new Error(`No "${scheme}" link in ${catalogKey}/${productId}`); } - return url; + return link; } diff --git a/examples/utils/wmts-utils.js b/examples/utils/wmts-utils.js index 5a18c4b..fa4985e 100644 --- a/examples/utils/wmts-utils.js +++ b/examples/utils/wmts-utils.js @@ -42,22 +42,28 @@ export function extractWmtsTileTemplate(capabilitiesXml, layerName, format) { /** * Resolves the raster catalog entry for a product, fetches its WMTS capabilities, - * and returns the tile URL template for the `${productId}-${productType}` layer. + * and returns the tile URL template along with the layer name from the catalog. * * Convenience helper that wraps the full catalog → capabilities → template chain. * * @param {string} productId - Raster product identifier. * @param {string} productType - Raster product type. * @param {string} [format] - Optional MIME type filter passed to `extractWmtsTileTemplate`. - * @returns {Promise} Tile URL template (still contains WMTS placeholders). + * @returns {Promise<{ template: string, name: string }>} Tile URL template (still contains WMTS placeholders) and the layer name reported by the catalog. * @throws If the catalog lookup, capabilities fetch, or layer extraction fails. */ export async function fetchWmtsTileTemplate(productId, productType, format) { - const capabilitiesUrl = await fetchServiceLink('raster', productId, productType, RASTER_SCHEME); + const { url: capabilitiesUrl, name } = await fetchServiceLink( + 'raster', + productId, + productType, + RASTER_SCHEME + ); // Capabilities endpoint is token-gated; same token is later used per-tile by the caller. const res = await fetch(`${capabilitiesUrl}?token=${TOKEN}`); if (!res.ok) { throw new Error(`Fetching WMTS capabilities failed: ${res.status}`); } - return extractWmtsTileTemplate(await res.text(), `${productId}-${productType}`, format); + const template = extractWmtsTileTemplate(await res.text(), name, format); + return { template, name }; } From fcc49ea5822a9b5c03ab6580a79b943c8a153dc0 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 11 Jun 2026 17:28:39 +0300 Subject: [PATCH 19/21] fix: cesium examples use wrong attributes and types --- examples/cesium-3d/3d-model.js | 28 +++++++++++--------- examples/cesium-geocoding/cesium.js | 28 +++++++++++--------- examples/cesium-layers-split/split-layers.js | 28 +++++++++++--------- examples/cesium-terrain/cesium.js | 28 +++++++++++--------- examples/cesium-viewshed/viewshed.js | 28 +++++++++++--------- examples/cesium-wmts/cesium.js | 28 +++++++++++--------- 6 files changed, 90 insertions(+), 78 deletions(-) diff --git a/examples/cesium-3d/3d-model.js b/examples/cesium-3d/3d-model.js index ce69dd5..9698ebd 100644 --- a/examples/cesium-3d/3d-model.js +++ b/examples/cesium-3d/3d-model.js @@ -23,19 +23,21 @@ Promise.all([ fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME) ]).then(([raster, dem, model]) => { const viewer = new Cesium.Viewer('cesiumContainer', { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: raster.template, - queryParameters: { - token: TOKEN - } - }), - layer: raster.name, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: 'WorldCRS84', - tilingScheme: new Cesium.GeographicTilingScheme() - }), + baseLayer: new Cesium.ImageryLayer( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: raster.template, + queryParameters: { + token: TOKEN + } + }), + layer: raster.name, + style: 'default', + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: 'WorldCRS84', + tilingScheme: new Cesium.GeographicTilingScheme() + }) + ), terrainProvider: new Cesium.CesiumTerrainProvider({ url: new Cesium.Resource({ url: dem.url, diff --git a/examples/cesium-geocoding/cesium.js b/examples/cesium-geocoding/cesium.js index b824f49..14417e2 100644 --- a/examples/cesium-geocoding/cesium.js +++ b/examples/cesium-geocoding/cesium.js @@ -44,19 +44,21 @@ fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then(({ temp timeline: false, navigationHelpButton: false, shouldAnimate: false, - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: template, - queryParameters: { - token: TOKEN - } - }), - layer: name, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: 'WorldCRS84', - tilingScheme: new Cesium.GeographicTilingScheme() - }), + baseLayer: new Cesium.ImageryLayer( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: template, + queryParameters: { + token: TOKEN + } + }), + layer: name, + style: 'default', + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: 'WorldCRS84', + tilingScheme: new Cesium.GeographicTilingScheme() + }) + ), geocoder: new OpenStreetMapNominatimGeocoder() }); }); diff --git a/examples/cesium-layers-split/split-layers.js b/examples/cesium-layers-split/split-layers.js index 2015443..ca2b78e 100644 --- a/examples/cesium-layers-split/split-layers.js +++ b/examples/cesium-layers-split/split-layers.js @@ -8,19 +8,21 @@ Promise.all([ fetchWmtsTileTemplate('OSM', 'RasterVectorBest', LAYER_IMAGE_FORMAT) ]).then(([main, second]) => { const viewer = new Cesium.Viewer('cesiumContainer', { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: main.template, - queryParameters: { - token: TOKEN - } - }), - layer: main.name, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: 'WorldCRS84', - tilingScheme: new Cesium.GeographicTilingScheme() - }), + baseLayer: new Cesium.ImageryLayer( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: main.template, + queryParameters: { + token: TOKEN + } + }), + layer: main.name, + style: 'default', + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: 'WorldCRS84', + tilingScheme: new Cesium.GeographicTilingScheme() + }) + ), baseLayerPicker: false, infoBox: false }); diff --git a/examples/cesium-terrain/cesium.js b/examples/cesium-terrain/cesium.js index b2fb41e..1424df5 100644 --- a/examples/cesium-terrain/cesium.js +++ b/examples/cesium-terrain/cesium.js @@ -17,19 +17,21 @@ Promise.all([ fetchServiceLink('dem', DEM_PRODUCT_ID, DEM_PRODUCT_TYPE, DEM_SCHEME) ]).then(([raster, dem]) => { const viewer = new Cesium.Viewer('cesiumContainer', { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: raster.template, - queryParameters: { - token: TOKEN - } - }), - layer: raster.name, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: 'newGrids', - tilingScheme: new Cesium.GeographicTilingScheme() - }), + baseLayer: new Cesium.ImageryLayer( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: raster.template, + queryParameters: { + token: TOKEN + } + }), + layer: raster.name, + style: 'default', + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: 'newGrids', + tilingScheme: new Cesium.GeographicTilingScheme() + }) + ), terrainProvider: new Cesium.CesiumTerrainProvider({ url: new Cesium.Resource({ url: dem.url, diff --git a/examples/cesium-viewshed/viewshed.js b/examples/cesium-viewshed/viewshed.js index 177e8ec..874cfeb 100644 --- a/examples/cesium-viewshed/viewshed.js +++ b/examples/cesium-viewshed/viewshed.js @@ -576,19 +576,21 @@ Promise.all([ fetchServiceLink('3d', MODEL_3D_PRODUCT_ID, MODEL_3D_PRODUCT_TYPE, MODEL_3D_SCHEME) ]).then(([raster, dem, model]) => { viewer = new Cesium.Viewer('cesiumContainer', { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: raster.template, - queryParameters: { - token: TOKEN - } - }), - layer: raster.name, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: 'WorldCRS84', - tilingScheme: new Cesium.GeographicTilingScheme() - }), + baseLayer: new Cesium.ImageryLayer( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: raster.template, + queryParameters: { + token: TOKEN + } + }), + layer: raster.name, + style: 'default', + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: 'WorldCRS84', + tilingScheme: new Cesium.GeographicTilingScheme() + }) + ), terrainProvider: new Cesium.CesiumTerrainProvider({ url: new Cesium.Resource({ url: dem.url, diff --git a/examples/cesium-wmts/cesium.js b/examples/cesium-wmts/cesium.js index bb4f7ff..af72d81 100644 --- a/examples/cesium-wmts/cesium.js +++ b/examples/cesium-wmts/cesium.js @@ -4,18 +4,20 @@ import { fetchWmtsTileTemplate } from './utils/wmts-utils.js'; fetchWmtsTileTemplate(PRODUCT_ID, PRODUCT_TYPE, LAYER_IMAGE_FORMAT).then(({ template, name }) => { new Cesium.Viewer('cesiumContainer', { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: template, - queryParameters: { - token: TOKEN - } - }), - layer: name, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: 'WorldCRS84', - tilingScheme: new Cesium.GeographicTilingScheme() - }) + baseLayer: new Cesium.ImageryLayer( + new Cesium.WebMapTileServiceImageryProvider({ + url: new Cesium.Resource({ + url: template, + queryParameters: { + token: TOKEN + } + }), + layer: name, + style: 'default', + format: LAYER_IMAGE_FORMAT, + tileMatrixSetID: 'WorldCRS84', + tilingScheme: new Cesium.GeographicTilingScheme() + }) + ) }); }); From 89790b80d45275f4739ba6504eeeae9c4a557629 Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Thu, 11 Jun 2026 17:57:36 +0300 Subject: [PATCH 20/21] chore: delete unused example files --- examples/cesium.html | 1 - examples/cesium.js | 18 --- examples/cesium_basic.js | 15 -- examples/cesium_wmts.js | 18 --- examples/leaflet.css | 3 - examples/leaflet.html | 1 - examples/leaflet_basic.js | 6 - examples/openlayers.css | 6 - examples/openlayers.html | 1 - examples/openlayers_basic.js | 5 - examples/openlayers_geojson.js | 241 --------------------------------- 11 files changed, 315 deletions(-) delete mode 100644 examples/cesium.html delete mode 100644 examples/cesium.js delete mode 100644 examples/cesium_basic.js delete mode 100644 examples/cesium_wmts.js delete mode 100644 examples/leaflet.css delete mode 100644 examples/leaflet.html delete mode 100644 examples/leaflet_basic.js delete mode 100644 examples/openlayers.css delete mode 100644 examples/openlayers.html delete mode 100644 examples/openlayers_basic.js delete mode 100644 examples/openlayers_geojson.js diff --git a/examples/cesium.html b/examples/cesium.html deleted file mode 100644 index 95872da..0000000 --- a/examples/cesium.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/examples/cesium.js b/examples/cesium.js deleted file mode 100644 index 388b7bd..0000000 --- a/examples/cesium.js +++ /dev/null @@ -1,18 +0,0 @@ -import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; - -const viewer = new Cesium.Viewer('cesiumContainer', { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } - }), - layer: LAYER_NAME, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: 'WorldCRS84', - tilingScheme: new Cesium.GeographicTilingScheme() - }) -}); diff --git a/examples/cesium_basic.js b/examples/cesium_basic.js deleted file mode 100644 index 7653d76..0000000 --- a/examples/cesium_basic.js +++ /dev/null @@ -1,15 +0,0 @@ -const viewer = new Cesium.Viewer('cesiumContainer', {}); - -const osm = new Cesium.OpenStreetMapImageryProvider({ - url: 'https://a.tile.openstreetmap.org/' -}); - -viewer.imageryLayers.addImageryProvider(osm); - -viewer.camera.flyTo({ - destination: Cesium.Cartesian3.fromDegrees(-122.4175, 37.655, 400), - orientation: { - heading: Cesium.Math.toRadians(0.0), - pitch: Cesium.Math.toRadians(-15.0) - } -}); diff --git a/examples/cesium_wmts.js b/examples/cesium_wmts.js deleted file mode 100644 index 742247d..0000000 --- a/examples/cesium_wmts.js +++ /dev/null @@ -1,18 +0,0 @@ -import { TOKEN } from './config/common-config.js'; -import { RASTER_SERVICE_URL, LAYER_NAME, LAYER_IMAGE_FORMAT } from './config/raster-config.js'; - -const viewer = new Cesium.Viewer('cesiumContainer', { - imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ - url: new Cesium.Resource({ - url: RASTER_SERVICE_URL, - queryParameters: { - token: TOKEN - } - }), - layer: LAYER_NAME, - style: 'default', - format: LAYER_IMAGE_FORMAT, - tileMatrixSetID: '', - tilingScheme: new Cesium.GeographicTilingScheme() - }) -}); diff --git a/examples/leaflet.css b/examples/leaflet.css deleted file mode 100644 index 63c0413..0000000 --- a/examples/leaflet.css +++ /dev/null @@ -1,3 +0,0 @@ -#map { - height: 100%; -} diff --git a/examples/leaflet.html b/examples/leaflet.html deleted file mode 100644 index ad19e7d..0000000 --- a/examples/leaflet.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/examples/leaflet_basic.js b/examples/leaflet_basic.js deleted file mode 100644 index b5e745e..0000000 --- a/examples/leaflet_basic.js +++ /dev/null @@ -1,6 +0,0 @@ -const map = L.map('map').setView([51.505, -0.09], 13); - -L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { - maxZoom: 19, - attribution: '© OpenStreetMap' -}).addTo(map); diff --git a/examples/openlayers.css b/examples/openlayers.css deleted file mode 100644 index 3e6b562..0000000 --- a/examples/openlayers.css +++ /dev/null @@ -1,6 +0,0 @@ -#map { - position: absolute; - top: 0; - bottom: 0; - width: 100%; -} diff --git a/examples/openlayers.html b/examples/openlayers.html deleted file mode 100644 index ad19e7d..0000000 --- a/examples/openlayers.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/examples/openlayers_basic.js b/examples/openlayers_basic.js deleted file mode 100644 index 7f75217..0000000 --- a/examples/openlayers_basic.js +++ /dev/null @@ -1,5 +0,0 @@ -const map = new ol.Map({ - target: 'map', - layers: [new ol.layer.Tile({ source: new ol.source.OSM() })], - view: new ol.View({ center: [0, 0], zoom: 2 }) -}); diff --git a/examples/openlayers_geojson.js b/examples/openlayers_geojson.js deleted file mode 100644 index b799445..0000000 --- a/examples/openlayers_geojson.js +++ /dev/null @@ -1,241 +0,0 @@ -const image = new ol.style.Circle({ - radius: 5, - fill: null, - stroke: new ol.style.Stroke({ color: 'red', width: 1 }) -}); - -const styles = { - Point: new ol.style.Style({ - image: image - }), - LineString: new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'green', - width: 1 - }) - }), - MultiLineString: new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'green', - width: 1 - }) - }), - MultiPoint: new ol.style.Style({ - image: image - }), - MultiPolygon: new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'yellow', - width: 1 - }), - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 0, 0.1)' - }) - }), - Polygon: new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'blue', - lineDash: [4], - width: 3 - }), - fill: new ol.style.Fill({ - color: 'rgba(0, 0, 255, 0.1)' - }) - }), - GeometryCollection: new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'magenta', - width: 2 - }), - fill: new ol.style.Fill({ - color: 'magenta' - }), - image: new ol.style.Circle({ - radius: 10, - fill: null, - stroke: new ol.style.Stroke({ - color: 'magenta' - }) - }) - }), - Circle: new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'red', - width: 2 - }), - fill: new ol.style.Fill({ - color: 'rgba(255,0,0,0.2)' - }) - }) -}; - -const styleFunction = function (feature) { - return styles[feature.getGeometry().getType()]; -}; - -const geojsonObject = { - type: 'FeatureCollection', - crs: { - type: 'name', - properties: { - name: 'EPSG:3857' - } - }, - features: [ - { - type: 'Feature', - geometry: { - type: 'Point', - coordinates: [0, 0] - } - }, - { - type: 'Feature', - geometry: { - type: 'LineString', - coordinates: [ - [4e6, -2e6], - [8e6, 2e6] - ] - } - }, - { - type: 'Feature', - geometry: { - type: 'LineString', - coordinates: [ - [4e6, 2e6], - [8e6, -2e6] - ] - } - }, - { - type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [ - [ - [-5e6, -1e6], - [-3e6, -1e6], - [-4e6, 1e6], - [-5e6, -1e6] - ] - ] - } - }, - { - type: 'Feature', - geometry: { - type: 'MultiLineString', - coordinates: [ - [ - [-1e6, -7.5e5], - [-1e6, 7.5e5] - ], - [ - [1e6, -7.5e5], - [1e6, 7.5e5] - ], - [ - [-7.5e5, -1e6], - [7.5e5, -1e6] - ], - [ - [-7.5e5, 1e6], - [7.5e5, 1e6] - ] - ] - } - }, - { - type: 'Feature', - geometry: { - type: 'MultiPolygon', - coordinates: [ - [ - [ - [-5e6, 6e6], - [-3e6, 6e6], - [-3e6, 8e6], - [-5e6, 8e6], - [-5e6, 6e6] - ] - ], - [ - [ - [-2e6, 6e6], - [0, 6e6], - [0, 8e6], - [-2e6, 8e6], - [-2e6, 6e6] - ] - ], - [ - [ - [1e6, 6e6], - [3e6, 6e6], - [3e6, 8e6], - [1e6, 8e6], - [1e6, 6e6] - ] - ] - ] - } - }, - { - type: 'Feature', - geometry: { - type: 'GeometryCollection', - geometries: [ - { - type: 'LineString', - coordinates: [ - [-5e6, -5e6], - [0, -5e6] - ] - }, - { - type: 'Point', - coordinates: [4e6, -5e6] - }, - { - type: 'Polygon', - coordinates: [ - [ - [1e6, -6e6], - [3e6, -6e6], - [2e6, -4e6], - [1e6, -6e6] - ] - ] - } - ] - } - } - ] -}; - -const vectorSource = new ol.source.Vector({ - features: new ol.format.GeoJSON().readFeatures(geojsonObject) -}); - -vectorSource.addFeature(new ol.Feature(new ol.geom.Circle([5e6, 7e6], 1e6))); - -const vectorLayer = new ol.layer.Vector({ - source: vectorSource, - style: styleFunction -}); - -const map = new ol.Map({ - layers: [ - new ol.layer.Tile({ - source: new ol.source.OSM() - }), - vectorLayer - ], - target: 'map', - view: new ol.View({ - center: [0, 0], - zoom: 2 - }) -}); From 7a7fc25e2bc7630d08e9b5d989c3f22e891ee5fc Mon Sep 17 00:00:00 2001 From: shimoncohen Date: Fri, 12 Jun 2026 00:17:43 +0300 Subject: [PATCH 21/21] refactor(upload-examples): migrate from bash to ZX --- package-lock.json | 16 +++- package.json | 7 +- scripts/upload-examples.mjs | 109 ++++++++++++++++++++++++ scripts/upload-examples.sh | 159 ------------------------------------ 4 files changed, 128 insertions(+), 163 deletions(-) create mode 100644 scripts/upload-examples.mjs delete mode 100755 scripts/upload-examples.sh diff --git a/package-lock.json b/package-lock.json index 91e0588..27d5e95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,8 @@ "tslib": "^2.4.1", "typescript": "~5.4.0", "vite": "^4.3.0", - "vite-plugin-static-copy": "^0.15.0" + "vite-plugin-static-copy": "^0.15.0", + "zx": "^8.8.5" } }, "node_modules/@algolia/abtesting": { @@ -5784,6 +5785,19 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zx": { + "version": "8.8.5", + "resolved": "https://registry.npmjs.org/zx/-/zx-8.8.5.tgz", + "integrity": "sha512-SNgDF5L0gfN7FwVOdEFguY3orU5AkfFZm9B5YSHog/UDHv+lvmd82ZAsOenOkQixigwH2+yyH198AwNdKhj+RA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "zx": "build/cli.js" + }, + "engines": { + "node": ">= 12.17.0" + } } } } diff --git a/package.json b/package.json index 7fd64b2..51b8c0a 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --plugin-search-dir . --check . && eslint .", "format": "prettier --plugin-search-dir . --write .", - "upload-examples": "bash scripts/upload-examples.sh", - "upload-all": "bash scripts/upload-examples.sh --assets" + "upload-examples": "zx scripts/upload-examples.mjs", + "upload-all": "zx scripts/upload-examples.mjs --assets" }, "devDependencies": { "@sveltejs/adapter-auto": "^2.0.0", @@ -40,7 +40,8 @@ "tslib": "^2.4.1", "typescript": "~5.4.0", "vite": "^4.3.0", - "vite-plugin-static-copy": "^0.15.0" + "vite-plugin-static-copy": "^0.15.0", + "zx": "^8.8.5" }, "type": "module", "dependencies": { diff --git a/scripts/upload-examples.mjs b/scripts/upload-examples.mjs new file mode 100644 index 0000000..79486a7 --- /dev/null +++ b/scripts/upload-examples.mjs @@ -0,0 +1,109 @@ +#!/usr/bin/env zx +// Upload all files under examples/ to S3 using @aws-sdk/client-s3. +// New and changed files (MD5 vs S3 ETag) are uploaded; identical files are skipped. +// Reads AWS_* env vars (same as the app). +// +// Usage: +// npx zx scripts/upload-examples.mjs [--assets|-a] [examples-dir] +// +// --assets / -a also upload the examples/assets/ folder (omit to skip it) + +import { createHash } from 'node:crypto'; +import { fileURLToPath } from 'node:url'; +import { paginateListObjectsV2, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'; +import { argv, dotenv, echo, fs, glob, path } from 'zx'; + +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); + +const envFile = path.join(repoRoot, '.env'); +if (fs.existsSync(envFile)) dotenv.config(envFile); + +const includeAssets = argv.assets || argv.a || false; +const examplesDir = argv._[0] ? path.resolve(argv._[0]) : path.join(repoRoot, 'examples'); +const parallelism = Number(process.env.UPLOAD_PARALLELISM ?? 32); + +const bucket = process.env.AWS_BUCKET; +if (!bucket) { + echo('ERROR: AWS_BUCKET is required'); + process.exit(1); +} +if (!(await fs.pathExists(examplesDir))) { + echo(`ERROR: examples directory not found: ${examplesDir}`); + process.exit(1); +} + +const client = new S3Client({ + endpoint: process.env.AWS_ENDPOINT_URL, + forcePathStyle: true, + region: process.env.AWS_REGION ?? 'us-east-1' +}); + +const CONTENT_TYPES = { + '.html': 'text/html', + '.css': 'text/css', + '.js': 'text/javascript', + '.json': 'application/json', + '.txt': 'text/plain', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.gif': 'image/gif' +}; + +// Fetch all existing S3 keys + ETags. +echo('Fetching existing S3 objects...'); +const etagByKey = new Map(); +for await (const page of paginateListObjectsV2({ client }, { Bucket: bucket })) { + for (const { Key, ETag } of page.Contents ?? []) { + etagByKey.set(Key, ETag.replaceAll('"', '')); + } +} +echo(`Found ${etagByKey.size} existing objects in S3.\n`); + +// Collect local files whose MD5 differs from the S3 ETag. +// ETag equals MD5 for non-multipart uploads, which holds for everything PutObject sends. +const files = await glob('**/*', { + cwd: examplesDir, + ignore: includeAssets ? [] : ['assets/**'] +}); + +const toUpload = []; +for (const key of files.sort()) { + const body = await fs.readFile(path.join(examplesDir, key)); + const md5 = createHash('md5').update(body).digest('hex'); + if (etagByKey.get(key) !== md5) { + toUpload.push({ key, body, isNew: !etagByKey.has(key) }); + } +} +echo(`${files.length - toUpload.length} files unchanged, ${toUpload.length} to upload.\n`); + +// Promise pool: `parallelism` workers pulling from a shared iterator. +const counts = { uploaded: 0, updated: 0, failed: 0 }; +const iter = toUpload[Symbol.iterator](); +await Promise.all( + Array.from({ length: parallelism }, async () => { + for (const { key, body, isNew } of iter) { + try { + await client.send( + new PutObjectCommand({ + Bucket: bucket, + Key: key, + Body: body, + ContentType: CONTENT_TYPES[path.extname(key)] ?? 'application/octet-stream' + }) + ); + echo(`${isNew ? 'UP' : 'UPDATE'} ${key}`); + counts[isNew ? 'uploaded' : 'updated']++; + } catch (err) { + echo(`FAIL ${key} (${err.message ?? err})`); + counts.failed++; + } + } + }) +); + +echo( + `\nDone — uploaded: ${counts.uploaded} new, ${counts.updated} updated, ${ + files.length - toUpload.length + } skipped, ${counts.failed} failed` +); +if (counts.failed > 0) process.exit(1); diff --git a/scripts/upload-examples.sh b/scripts/upload-examples.sh deleted file mode 100755 index e33a8c3..0000000 --- a/scripts/upload-examples.sh +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Upload all files under examples/ to S3. -# - New files are uploaded. -# - Existing files are uploaded only if their content differs (MD5 vs S3 ETag). -# - Identical files are skipped. -# Reads AWS_* env vars (same as the app). -# -# Usage: -# ./scripts/upload-examples.sh [--assets|-a] [examples-dir] -# -# --assets / -a also upload the examples/assets/ folder (omit to skip it) -# -# The optional examples-dir argument overrides the default examples/ directory. - -declare -A CMD_INSTALL=( - [aws]="AWS CLI v2 — https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html - Linux: curl 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' -o awscliv2.zip && unzip awscliv2.zip && sudo ./aws/install - macOS: brew install awscli - NOTE: avoid 'sudo apt install awscli' — the apt package (v1) conflicts with newer botocore" -) - -for cmd in "${!CMD_INSTALL[@]}"; do - if ! command -v "$cmd" &> /dev/null; then - echo "WARNING: '$cmd' is not installed or not in PATH." >&2 - echo " Install: ${CMD_INSTALL[$cmd]}" >&2 - exit 1 - fi -done - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" - -# Load .env if present -if [[ -f "$REPO_ROOT/.env" ]]; then - set -a - # shellcheck disable=SC1091 - source "$REPO_ROOT/.env" - set +a -fi - -INCLUDE_ASSETS=false -while [[ $# -gt 0 ]]; do - case "$1" in - -a|--assets) INCLUDE_ASSETS=true; shift ;; - -*) echo "ERROR: unknown option '$1'" >&2; exit 1 ;; - *) break ;; - esac -done - -EXAMPLES_DIR="${1:-$REPO_ROOT/examples}" -BUCKET="${AWS_BUCKET:?AWS_BUCKET is required}" -ENDPOINT="${AWS_ENDPOINT_URL:-}" -REGION="${AWS_REGION:-us-east-1}" -PARALLELISM="${UPLOAD_PARALLELISM:-8}" - -if [[ ! -d "$EXAMPLES_DIR" ]]; then - echo "ERROR: examples directory not found: $EXAMPLES_DIR" >&2 - exit 1 -fi - -ENDPOINT_FLAG="" -if [[ -n "$ENDPOINT" ]]; then - ENDPOINT_FLAG="--endpoint-url $ENDPOINT" -fi - -# Fetch all existing S3 keys + ETags in one list-objects call. -# Output format per line: \t (ETag has surrounding quotes stripped) -echo "Fetching existing S3 objects..." -s3_index=$(mktemp) -trap 'rm -f "$s3_index"' EXIT - -aws s3api list-objects-v2 \ - --bucket "$BUCKET" \ - --region "$REGION" \ - $ENDPOINT_FLAG \ - --query 'Contents[].[Key, ETag]' \ - --output text 2>/dev/null \ - | sed 's/"//g' \ - | sort -k1,1 > "$s3_index" || true - -existing_count=$(wc -l < "$s3_index") -echo "Found $existing_count existing objects in S3." -echo "" - -# Temp dir for inter-process counters and upload list -tmp_dir=$(mktemp -d) -trap 'rm -f "$s3_index"; rm -rf "$tmp_dir"' EXIT -touch "$tmp_dir/uploaded" "$tmp_dir/updated" "$tmp_dir/skipped" "$tmp_dir/failed" -to_upload="$tmp_dir/to_upload" - -# Classify each local file in the main process. -# Subshells (xargs workers) only handle the actual aws s3 cp calls. -while IFS= read -r -d '' file; do - key="${file#$EXAMPLES_DIR/}" - local_md5=$(md5sum "$file" | cut -d' ' -f1) - - s3_entry=$(grep -P "^${key}\t" "$s3_index" || true) - - if [[ -z "$s3_entry" ]]; then - # New file - printf '%s\0' "new|$file" >> "$to_upload" - else - s3_etag=$(printf '%s' "$s3_entry" | awk '{print $2}') - if [[ "$local_md5" == "$s3_etag" ]]; then - echo "SKIP $key" - echo 1 >> "$tmp_dir/skipped" - else - # Changed file — overwrite - printf '%s\0' "update|$file" >> "$to_upload" - fi - fi -done < <( - if [[ "$INCLUDE_ASSETS" == "false" ]]; then - find "$EXAMPLES_DIR" -type f -not -path "$EXAMPLES_DIR/assets/*" -print0 - else - find "$EXAMPLES_DIR" -type f -print0 - fi | sort -z - ) - -upload_file() { - local mode file key label - mode="${1%%|*}" - file="${1#*|}" - key="${file#$EXAMPLES_DIR/}" - label=$([ "$mode" = "update" ] && echo "UPDATE" || echo "UP") - - if aws s3 cp \ - "$file" \ - "s3://$BUCKET/$key" \ - --region "$REGION" \ - $ENDPOINT_FLAG \ - > /dev/null 2>&1; then - echo "$label $key" - echo 1 >> "$tmp_dir/$mode"d - else - echo "FAIL $key" >&2 - echo 1 >> "$tmp_dir/failed" - fi -} -export -f upload_file -export EXAMPLES_DIR BUCKET REGION ENDPOINT_FLAG tmp_dir - -if [[ -s "$to_upload" ]]; then - xargs -0 -P "$PARALLELISM" -I{} bash -c 'upload_file "$@"' _ {} < "$to_upload" -fi - -uploaded=$(wc -l < "$tmp_dir/uploaded") -updated=$(wc -l < "$tmp_dir/updated") -skipped=$(wc -l < "$tmp_dir/skipped") -failed=$(wc -l < "$tmp_dir/failed") - -echo "" -echo "Done — uploaded: $uploaded new, $updated updated, $skipped skipped, $failed failed" - -if ((failed > 0)); then - exit 1 -fi