import { create as create2, fromTransform } from "./chunk-E7S7Q7VV.js"; import { VectorEventType_default } from "./chunk-V7WRBSQ6.js"; import { Feature_default } from "./chunk-W7BDJOQY.js"; import { DataTile_default, LRUCache_default, TileLayer_default, TileProperty_default, asArrayLike, asImageLike } from "./chunk-UNDFRJ2M.js"; import { BuilderGroup_default, DECLUTTER, ExecutorGroup_default, HIT_DETECT_RESOLUTION, createHitDetectionImageData, getSquaredTolerance, hitDetect, renderFeature } from "./chunk-T3TT2KJN.js"; import { Layer_default, ZIndexContext_default } from "./chunk-ZUI5NXIU.js"; import { BaseVector_default, BooleanType, CallExpression, ColorType, NumberArrayType, NumberType, Ops, SizeType, StringType, computeGeometryType, isType, newParsingContext, parse, typeName } from "./chunk-ZCRXKB7J.js"; import { EventType_default as EventType_default2, Event_default } from "./chunk-I6K7MRGV.js"; import { asArray } from "./chunk-PGWX4545.js"; import { Property_default } from "./chunk-AYBYZSAV.js"; import { ViewHint_default } from "./chunk-YLJGUH5Z.js"; import { inflateEnds, transform2D } from "./chunk-AZGMK675.js"; import { ImageTile_default, TileRange_default, Tile_default2 as Tile_default, createOrUpdate2 as createOrUpdate, getKey } from "./chunk-7XMWB3J4.js"; import { TileState_default } from "./chunk-5D2XPBR2.js"; import { toSize } from "./chunk-SHUBVYN4.js"; import { apply, compose, create, makeInverse, multiply, reset, rotate, scale, setFromArray, translate } from "./chunk-X52LGBOS.js"; import { assert } from "./chunk-QFCIXVZ3.js"; import { equivalent, fromUserExtent, getTransform, getTransformFromProjections, getUserProjection, toUserExtent, toUserResolution, transformExtent, wrapX } from "./chunk-A3RXLHYB.js"; import { clamp } from "./chunk-54BTDBAD.js"; import { createCanvasContext2D } from "./chunk-UPTVWZ45.js"; import { SAFARI_BUG_237906 } from "./chunk-5XHD7RSF.js"; import { abstract, getUid } from "./chunk-Q5ZULJHM.js"; import { Disposable_default, Target_default, listen, unlistenByKey } from "./chunk-NGFXCWUF.js"; import { EventType_default, ascending, descending, equals } from "./chunk-K25ZO44T.js"; import { boundingExtent, buffer, containsCoordinate, containsExtent, createEmpty, equals as equals2, getIntersection, getRotatedViewport, getTopLeft, getWidth, intersects, isEmpty } from "./chunk-SRXHWJOY.js"; import { clear } from "./chunk-5RHQVMYD.js"; // node_modules/ol/renderer/canvas/VectorTileLayer.js var IMAGE_REPLAYS = { "image": ["Polygon", "Circle", "LineString", "Image", "Text"], "hybrid": ["Polygon", "LineString"], "vector": [] }; var VECTOR_REPLAYS = { "hybrid": ["Image", "Text", "Default"], "vector": ["Polygon", "Circle", "LineString", "Image", "Text", "Default"] }; var CanvasVectorTileLayerRenderer = class extends TileLayer_default { /** * @param {import("../../layer/VectorTile.js").default} layer VectorTile layer. * @param {import("./TileLayer.js").Options} options Options. */ constructor(layer, options) { super(layer, options); this.boundHandleStyleImageChange_ = this.handleStyleImageChange_.bind(this); this.renderedLayerRevision_; this.renderedPixelToCoordinateTransform_ = null; this.renderedRotation_; this.renderedOpacity_ = 1; this.tmpTransform_ = create(); this.tileClipContexts_ = null; } /** * Determine whether tiles for next extent should be enqueued for rendering. * @return {boolean} Rendering tiles for next extent is supported. * @override */ enqueueTilesForNextExtent() { return this.getLayer().getRenderMode() !== "vector"; } /** * @param {import("../../VectorRenderTile.js").default} tile Tile. * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {number} x Left of the tile. * @param {number} y Top of the tile. * @param {number} w Width of the tile. * @param {number} h Height of the tile. * @param {number} gutter Tile gutter. * @param {boolean} transition Apply an alpha transition. * @override */ drawTile(tile, frameState, x, y, w, h, gutter, transition) { this.updateExecutorGroup_( tile, frameState.pixelRatio, frameState.viewState.projection ); if (this.tileImageNeedsRender_(tile)) { this.renderTileImage_(tile, frameState); } super.drawTile(tile, frameState, x, y, w, h, gutter, transition); } /** * @param {number} z Tile coordinate z. * @param {number} x Tile coordinate x. * @param {number} y Tile coordinate y. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {import("../../Tile.js").default|null} Tile (or null if outside source extent). * @override */ getTile(z, x, y, frameState) { const tile = ( /** @type {import("../../VectorRenderTile.js").default} */ this.getOrCreateTile(z, x, y, frameState) ); if (!tile) { return null; } const viewState = frameState.viewState; const resolution = viewState.resolution; const viewHints = frameState.viewHints; const source = this.getLayer().getSource(); const tileGrid = source.getTileGridForProjection(viewState.projection); const hifi = !(viewHints[ViewHint_default.ANIMATING] || viewHints[ViewHint_default.INTERACTING]); const withinTileResolutionRange = tileGrid.getZForResolution(resolution, source.zDirection) === z; if (hifi && withinTileResolutionRange) { tile.wantedResolution = resolution; } else if (!tile.wantedResolution) { tile.wantedResolution = tileGrid.getResolution(z); } return tile; } /** * Determine whether render should be called. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {boolean} Layer is ready to be rendered. * @override */ prepareFrame(frameState) { const layerRevision = this.getLayer().getRevision(); if (this.renderedLayerRevision_ !== layerRevision) { this.renderedLayerRevision_ = layerRevision; this.renderedTiles.length = 0; } return super.prepareFrame(frameState); } /** * @param {import("../../VectorRenderTile.js").default} tile Tile. * @param {number} pixelRatio Pixel ratio. * @param {import("../../proj/Projection.js").default} projection Projection. * @private */ updateExecutorGroup_(tile, pixelRatio, projection) { const layer = ( /** @type {import("../../layer/VectorTile.js").default} */ this.getLayer() ); const revision = layer.getRevision(); const renderOrder = layer.getRenderOrder() || null; const resolution = tile.wantedResolution; const builderState = tile.getReplayState(layer); if (!builderState.dirty && builderState.renderedResolution === resolution && builderState.renderedRevision == revision && builderState.renderedRenderOrder == renderOrder) { return; } const source = layer.getSource(); const declutter = !!layer.getDeclutter(); const sourceTileGrid = source.getTileGrid(); const tileGrid = source.getTileGridForProjection(projection); const tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord); const sourceTiles = source.getSourceTiles(pixelRatio, projection, tile); const layerUid = getUid(layer); delete tile.hitDetectionImageData[layerUid]; tile.executorGroups[layerUid] = []; builderState.dirty = false; for (let t = 0, tt = sourceTiles.length; t < tt; ++t) { const sourceTile = sourceTiles[t]; if (sourceTile.getState() != TileState_default.LOADED) { continue; } const sourceProjection = source.getProjection(); const sourceTileCoord = sourceTile.tileCoord; let sourceTileExtent = sourceTileGrid.getTileCoordExtent(sourceTileCoord); if (projection && sourceProjection && !equivalent(projection, sourceProjection)) { sourceTileExtent = transformExtent( sourceTileExtent, sourceProjection, projection, 32 ); } const sharedExtent = getIntersection(tileExtent, sourceTileExtent); const builderExtent = buffer( sharedExtent, layer.getRenderBuffer() * resolution, this.tempExtent ); const bufferedExtent = equals2(sourceTileExtent, sharedExtent) ? null : builderExtent; const builderGroup = new BuilderGroup_default( 0, sharedExtent, resolution, pixelRatio ); const squaredTolerance = getSquaredTolerance( resolution, pixelRatio ); const render = function(feature, index) { let styles; const styleFunction = feature.getStyleFunction() || layer.getStyleFunction(); if (styleFunction) { styles = styleFunction(feature, resolution); } if (styles) { const dirty = this.renderFeature( feature, squaredTolerance, styles, builderGroup, declutter, index ); builderState.dirty = builderState.dirty || dirty; } }; const features = sourceTile.getFeatures(); if (renderOrder && renderOrder !== builderState.renderedRenderOrder) { features.sort(renderOrder); } for (let i = 0, ii = features.length; i < ii; ++i) { let feature = features[i]; if (projection && sourceTile.projection && !equivalent(projection, sourceTile.projection)) { feature = feature.clone(); feature.getGeometry().applyTransform(getTransform(sourceTile.projection, projection)); } if (!bufferedExtent || intersects(bufferedExtent, feature.getGeometry().getExtent())) { render.call(this, feature, i); } } const executorGroupInstructions = builderGroup.finish(); const replayExtent = layer.getRenderMode() !== "vector" && declutter && sourceTiles.length === 1 ? null : sharedExtent; const renderingReplayGroup = new ExecutorGroup_default( replayExtent, resolution, pixelRatio, source.getOverlaps(), executorGroupInstructions, layer.getRenderBuffer(), true ); tile.executorGroups[layerUid].push(renderingReplayGroup); } builderState.renderedRevision = revision; builderState.renderedRenderOrder = renderOrder; builderState.renderedResolution = resolution; } /** * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate. * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {number} hitTolerance Hit tolerance in pixels. * @param {import("../vector.js").FeatureCallback} callback Feature callback. * @param {Array>} matches The hit detected matches with tolerance. * @return {T|undefined} Callback result. * @template T * @override */ forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, matches) { var _a, _b; const resolution = frameState.viewState.resolution; const rotation = frameState.viewState.rotation; hitTolerance = hitTolerance == void 0 ? 0 : hitTolerance; const layer = this.getLayer(); const source = layer.getSource(); const tileGrid = source.getTileGridForProjection( frameState.viewState.projection ); const hitExtent = boundingExtent([coordinate]); buffer(hitExtent, resolution * hitTolerance, hitExtent); const features = {}; const featureCallback = function(feature, geometry, distanceSq) { let key = feature.getId(); if (key === void 0) { key = getUid(feature); } const match = features[key]; if (!match) { if (distanceSq === 0) { features[key] = true; return callback(feature, layer, geometry); } matches.push( features[key] = { feature, layer, geometry, distanceSq, callback } ); } else if (match !== true && distanceSq < match.distanceSq) { if (distanceSq === 0) { features[key] = true; matches.splice(matches.lastIndexOf(match), 1); return callback(feature, layer, geometry); } match.geometry = geometry; match.distanceSq = distanceSq; } return void 0; }; const renderedTiles = ( /** @type {Array} */ this.renderedTiles ); const layerUid = getUid(layer); const declutter = layer.getDeclutter(); const declutteredFeatures = declutter ? (_b = (_a = frameState.declutter) == null ? void 0 : _a[declutter]) == null ? void 0 : _b.all().map((item) => item.value) : null; let found; foundFeature: for (let i = 0, ii = renderedTiles.length; i < ii; ++i) { const tile = renderedTiles[i]; const tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord); if (!intersects(tileExtent, hitExtent)) { continue; } const executorGroups = tile.executorGroups[layerUid]; for (let t = 0, tt = executorGroups.length; t < tt; ++t) { found = executorGroups[t].forEachFeatureAtCoordinate( coordinate, resolution, rotation, hitTolerance, featureCallback, declutteredFeatures ); if (found) { break foundFeature; } } } return found; } /** * Asynchronous layer level hit detection. * @param {import("../../pixel.js").Pixel} pixel Pixel. * @return {Promise>} Promise that resolves with an array of features. * @override */ getFeatures(pixel) { if (this.renderedTiles.length === 0) { return Promise.resolve([]); } return new Promise((resolve, reject) => { const layer = this.getLayer(); const source = layer.getSource(); const projection = this.renderedProjection; const projectionExtent = projection.getExtent(); const resolution = this.renderedResolution; const tileGrid = source.getTileGridForProjection(projection); const coordinate = apply( this.renderedPixelToCoordinateTransform_, pixel.slice() ); const tileCoordString = tileGrid.getTileCoordForCoordAndResolution(coordinate, resolution).toString(); const tile = ( /** @type {Array} */ this.renderedTiles.find( (tile2) => tile2.tileCoord.toString() === tileCoordString && tile2.getState() === TileState_default.LOADED ) ); if (!tile || tile.loadingSourceTiles > 0) { resolve([]); return; } if (source.getWrapX() && projection.canWrapX() && !containsExtent( projectionExtent, tileGrid.getTileCoordExtent(tile.tileCoord) )) { wrapX(coordinate, projection); } const layerUid = getUid(layer); const extent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord); const corner = getTopLeft(extent); const tilePixel = [ (coordinate[0] - corner[0]) / resolution, (corner[1] - coordinate[1]) / resolution ]; const features = tile.getSourceTiles().reduce( (accumulator, sourceTile) => accumulator.concat(sourceTile.getFeatures()), /** @type {Array} */ [] ); let hitDetectionImageData = tile.hitDetectionImageData[layerUid]; if (!hitDetectionImageData) { const tileSize = toSize( tileGrid.getTileSize( tileGrid.getZForResolution(resolution, source.zDirection) ) ); const rotation = this.renderedRotation_; const transforms = [ this.getRenderTransform( tileGrid.getTileCoordCenter(tile.wrappedTileCoord), resolution, 0, HIT_DETECT_RESOLUTION, tileSize[0] * HIT_DETECT_RESOLUTION, tileSize[1] * HIT_DETECT_RESOLUTION, 0 ) ]; hitDetectionImageData = createHitDetectionImageData( tileSize, transforms, features, layer.getStyleFunction(), tileGrid.getTileCoordExtent(tile.wrappedTileCoord), tile.getReplayState(layer).renderedResolution, rotation ); tile.hitDetectionImageData[layerUid] = hitDetectionImageData; } resolve(hitDetect(tilePixel, features, hitDetectionImageData)); }); } /** * @param {import("../../extent.js").Extent} extent Extent. * @return {Array} Features. */ getFeaturesInExtent(extent) { const features = []; const tileCache = this.getTileCache(); if (tileCache.getCount() === 0) { return features; } const source = this.getLayer().getSource(); const tileGrid = source.getTileGridForProjection( this.frameState.viewState.projection ); const z = tileGrid.getZForResolution(this.renderedResolution); const visitedSourceTiles = {}; tileCache.forEach((tile) => { if (tile.tileCoord[0] !== z || tile.getState() !== TileState_default.LOADED) { return; } const sourceTiles = tile.getSourceTiles(); for (let i = 0, ii = sourceTiles.length; i < ii; ++i) { const sourceTile = sourceTiles[i]; const key = sourceTile.getKey(); if (key in visitedSourceTiles) { continue; } visitedSourceTiles[key] = true; const tileCoord = sourceTile.tileCoord; if (intersects(extent, tileGrid.getTileCoordExtent(tileCoord))) { const tileFeatures = sourceTile.getFeatures(); if (tileFeatures) { for (let j = 0, jj = tileFeatures.length; j < jj; ++j) { const candidate = tileFeatures[j]; const geometry = candidate.getGeometry(); if (intersects(extent, geometry.getExtent())) { features.push(candidate); } } } } } }); return features; } /** * Perform action necessary to get the layer rendered after new fonts have loaded * @override */ handleFontsChanged() { const layer = this.getLayer(); if (layer.getVisible() && this.renderedLayerRevision_ !== void 0) { layer.changed(); } } /** * Handle changes in image style state. * @param {import("../../events/Event.js").default} event Image style change event. * @private */ handleStyleImageChange_(event) { this.renderIfReadyAndVisible(); } /** * Render declutter items for this layer * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {import("../../layer/Layer.js").State} layerState Layer state. */ renderDeclutter(frameState, layerState) { var _a; const context = this.context; const alpha = context.globalAlpha; context.globalAlpha = layerState.opacity; const viewHints = frameState.viewHints; const hifi = !(viewHints[ViewHint_default.ANIMATING] || viewHints[ViewHint_default.INTERACTING]); const scaledCanvasSize = [ this.context.canvas.width, this.context.canvas.height ]; const declutter = this.getLayer().getDeclutter(); const declutterTree = declutter ? (_a = frameState.declutter) == null ? void 0 : _a[declutter] : void 0; const layerUid = getUid(this.getLayer()); const tiles = ( /** @type {Array} */ this.renderedTiles ); for (let i = 0, ii = tiles.length; i < ii; ++i) { const tile = tiles[i]; const executorGroups = tile.executorGroups[layerUid]; if (executorGroups) { for (let j = executorGroups.length - 1; j >= 0; --j) { executorGroups[j].execute( this.context, scaledCanvasSize, this.getTileRenderTransform(tile, frameState), frameState.viewState.rotation, hifi, DECLUTTER, declutterTree ); } } } context.globalAlpha = alpha; } /** * @param {import("../../Map.js").FrameState} frameState Frame state. * @override */ renderDeferredInternal(frameState) { const tiles = ( /** @type {Array} */ this.renderedTiles ); const layerUid = getUid(this.getLayer()); const executorGroups = tiles.reduce( (acc, tile, index) => { tile.executorGroups[layerUid].forEach( (executorGroup) => acc.push({ executorGroup, index }) ); return acc; }, /** @type {Array<{executorGroup: CanvasExecutorGroup, index: number}>} */ [] ); const executorGroupZIndexContexts = executorGroups.map( ({ executorGroup }) => executorGroup.getDeferredZIndexContexts() ); const usedZIndices = {}; for (let i = 0, ii = executorGroups.length; i < ii; ++i) { const executorGroupZindexContext = executorGroups[i].executorGroup.getDeferredZIndexContexts(); for (const key in executorGroupZindexContext) { usedZIndices[key] = true; } } const zIndexKeys = Object.keys(usedZIndices).map(Number).sort(ascending); zIndexKeys.forEach((zIndex) => { executorGroupZIndexContexts.forEach((zIndexContexts, i) => { if (!zIndexContexts[zIndex]) { return; } zIndexContexts[zIndex].forEach((zIndexContext) => { const { executorGroup, index } = executorGroups[i]; const context = executorGroup.getRenderedContext(); const alpha = context.globalAlpha; context.globalAlpha = this.renderedOpacity_; const tileClipContext = this.tileClipContexts_[index]; if (tileClipContext) { tileClipContext.draw(context); } zIndexContext.draw(context); if (tileClipContext) { context.restore(); } context.globalAlpha = alpha; zIndexContext.clear(); }); zIndexContexts[zIndex].length = 0; }); }); } /** * @param {import("../../VectorRenderTile.js").default} tile The tile * @param {import('../../Map.js').FrameState} frameState Current frame state * @return {import('../../transform.js').Transform} Transform to use to render this tile */ getTileRenderTransform(tile, frameState) { const pixelRatio = frameState.pixelRatio; const viewState = frameState.viewState; const center = viewState.center; const resolution = viewState.resolution; const rotation = viewState.rotation; const size = frameState.size; const width = Math.round(size[0] * pixelRatio); const height = Math.round(size[1] * pixelRatio); const source = this.getLayer().getSource(); const tileGrid = source.getTileGridForProjection( frameState.viewState.projection ); const tileCoord = tile.tileCoord; const tileExtent = tileGrid.getTileCoordExtent(tile.wrappedTileCoord); const worldOffset = tileGrid.getTileCoordExtent(tileCoord, this.tempExtent)[0] - tileExtent[0]; const transform = multiply( scale(this.inversePixelTransform.slice(), 1 / pixelRatio, 1 / pixelRatio), this.getRenderTransform( center, resolution, rotation, pixelRatio, width, height, worldOffset ) ); return transform; } /** * Render the vectors for this layer. * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context Target context. * @param {import("../../Map.js").FrameState} frameState Frame state. * @override */ postRender(context, frameState) { var _a; const viewHints = frameState.viewHints; const hifi = !(viewHints[ViewHint_default.ANIMATING] || viewHints[ViewHint_default.INTERACTING]); this.renderedPixelToCoordinateTransform_ = frameState.pixelToCoordinateTransform.slice(); this.renderedRotation_ = frameState.viewState.rotation; this.renderedOpacity_ = frameState.layerStatesArray[frameState.layerIndex].opacity; const layer = ( /** @type {import("../../layer/VectorTile.js").default} */ this.getLayer() ); const renderMode = layer.getRenderMode(); const alpha = context.globalAlpha; context.globalAlpha = this.renderedOpacity_; const declutter = layer.getDeclutter(); const replayTypes = declutter ? VECTOR_REPLAYS[renderMode].filter((type) => !DECLUTTER.includes(type)) : VECTOR_REPLAYS[renderMode]; const viewState = frameState.viewState; const rotation = viewState.rotation; const tileSource = layer.getSource(); const tileGrid = tileSource.getTileGridForProjection(viewState.projection); const z = tileGrid.getZForResolution( viewState.resolution, tileSource.zDirection ); const tiles = ( /** @type {Array} */ this.renderedTiles ); const clips = []; const clipZs = []; const tileClipContexts = []; const layerUid = getUid(layer); let ready = true; for (let i = tiles.length - 1; i >= 0; --i) { const tile = tiles[i]; ready = ready && !tile.getReplayState(layer).dirty; const executorGroups = tile.executorGroups[layerUid].filter( (group) => group.hasExecutors(replayTypes) ); if (executorGroups.length === 0) { continue; } const transform = this.getTileRenderTransform(tile, frameState); const currentZ = tile.tileCoord[0]; let contextSaved = false; const currentClip = executorGroups[0].getClipCoords(transform); let clipContext = context; let tileClipContext; if (currentClip) { tileClipContext = new ZIndexContext_default(); clipContext = tileClipContext.getContext(); for (let j = 0, jj = clips.length; j < jj; ++j) { if (z !== currentZ && currentZ < clipZs[j]) { const clip = clips[j]; if (intersects( [ currentClip[0], currentClip[3], currentClip[4], currentClip[7] ], [clip[0], clip[3], clip[4], clip[7]] )) { if (!contextSaved) { clipContext.save(); contextSaved = true; } clipContext.beginPath(); clipContext.moveTo(currentClip[0], currentClip[1]); clipContext.lineTo(currentClip[2], currentClip[3]); clipContext.lineTo(currentClip[4], currentClip[5]); clipContext.lineTo(currentClip[6], currentClip[7]); clipContext.moveTo(clip[6], clip[7]); clipContext.lineTo(clip[4], clip[5]); clipContext.lineTo(clip[2], clip[3]); clipContext.lineTo(clip[0], clip[1]); clipContext.clip(); } } } clips.push(currentClip); clipZs.push(currentZ); } for (let t = 0, tt = executorGroups.length; t < tt; ++t) { const executorGroup = executorGroups[t]; executorGroup.execute( context, [context.canvas.width, context.canvas.height], transform, rotation, hifi, replayTypes, (_a = frameState.declutter) == null ? void 0 : _a[declutter] ); } if (contextSaved) { if (clipContext === context) { clipContext.restore(); } else { tileClipContexts[i] = tileClipContext; } } } context.globalAlpha = alpha; this.ready = ready; this.tileClipContexts_ = tileClipContexts; if (!frameState.declutter) { this.renderDeferredInternal(frameState); } super.postRender(context, frameState); } /** * @param {import("../../Feature.js").FeatureLike} feature Feature. * @param {number} squaredTolerance Squared tolerance. * @param {import("../../style/Style.js").default|Array} styles The style or array of styles. * @param {import("../../render/canvas/BuilderGroup.js").default} builderGroup Replay group. * @param {boolean} [declutter] Enable decluttering. * @param {number} [index] Render order index. * @return {boolean} `true` if an image is loading. */ renderFeature(feature, squaredTolerance, styles, builderGroup, declutter, index) { if (!styles) { return false; } let loading = false; if (Array.isArray(styles)) { for (let i = 0, ii = styles.length; i < ii; ++i) { loading = renderFeature( builderGroup, feature, styles[i], squaredTolerance, this.boundHandleStyleImageChange_, void 0, declutter, index ) || loading; } } else { loading = renderFeature( builderGroup, feature, styles, squaredTolerance, this.boundHandleStyleImageChange_, void 0, declutter, index ); } return loading; } /** * @param {import("../../VectorRenderTile.js").default} tile Tile. * @return {boolean} A new tile image was rendered. * @private */ tileImageNeedsRender_(tile) { const layer = ( /** @type {import("../../layer/VectorTile.js").default} */ this.getLayer() ); if (layer.getRenderMode() === "vector") { return false; } const replayState = tile.getReplayState(layer); const revision = layer.getRevision(); const resolution = tile.wantedResolution; const tileImageNeedsRender = replayState.renderedTileResolution !== resolution || replayState.renderedTileRevision !== revision; return tileImageNeedsRender; } /** * @param {import("../../VectorRenderTile.js").default} tile Tile. * @param {import("../../Map").FrameState} frameState Frame state. * @private */ renderTileImage_(tile, frameState) { const layer = ( /** @type {import("../../layer/VectorTile.js").default} */ this.getLayer() ); const replayState = tile.getReplayState(layer); const revision = layer.getRevision(); const executorGroups = tile.executorGroups[getUid(layer)]; replayState.renderedTileRevision = revision; const tileCoord = tile.wrappedTileCoord; const z = tileCoord[0]; const source = layer.getSource(); let pixelRatio = frameState.pixelRatio; const viewState = frameState.viewState; const projection = viewState.projection; const tileGrid = source.getTileGridForProjection(projection); const tileResolution = tileGrid.getResolution(tile.tileCoord[0]); const renderPixelRatio = frameState.pixelRatio / tile.wantedResolution * tileResolution; const resolution = tileGrid.getResolution(z); const context = tile.getContext(); pixelRatio = Math.round( Math.max(pixelRatio, renderPixelRatio / pixelRatio) ); const size = source.getTilePixelSize(z, pixelRatio, projection); context.canvas.width = size[0]; context.canvas.height = size[1]; const renderScale = pixelRatio / renderPixelRatio; if (renderScale !== 1) { const canvasTransform = reset(this.tmpTransform_); scale(canvasTransform, renderScale, renderScale); context.setTransform.apply(context, canvasTransform); } const tileExtent = tileGrid.getTileCoordExtent(tileCoord, this.tempExtent); const pixelScale = renderPixelRatio / resolution; const transform = reset(this.tmpTransform_); scale(transform, pixelScale, -pixelScale); translate(transform, -tileExtent[0], -tileExtent[3]); for (let i = 0, ii = executorGroups.length; i < ii; ++i) { const executorGroup = executorGroups[i]; executorGroup.execute( context, [ context.canvas.width * renderScale, context.canvas.height * renderScale ], transform, 0, true, IMAGE_REPLAYS[layer.getRenderMode()], null ); } replayState.renderedTileResolution = tile.wantedResolution; } }; var VectorTileLayer_default = CanvasVectorTileLayerRenderer; // node_modules/ol/layer/VectorTile.js var VectorTileLayer = class extends BaseVector_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options ? options : {}; const baseOptions = Object.assign({}, options); delete baseOptions.preload; const cacheSize = options.cacheSize === void 0 ? 0 : options.cacheSize; delete options.cacheSize; delete baseOptions.useInterimTilesOnError; super(baseOptions); this.on; this.once; this.un; this.cacheSize_ = cacheSize; const renderMode = options.renderMode || "hybrid"; assert( renderMode == "hybrid" || renderMode == "vector", "`renderMode` must be `'hybrid'` or `'vector'`" ); this.renderMode_ = renderMode; this.setPreload(options.preload ? options.preload : 0); this.setUseInterimTilesOnError( options.useInterimTilesOnError !== void 0 ? options.useInterimTilesOnError : true ); this.getBackground; this.setBackground; } /** * @override */ createRenderer() { return new VectorTileLayer_default(this, { cacheSize: this.cacheSize_ }); } /** * Get the topmost feature that intersects the given pixel on the viewport. Returns a promise * that resolves with an array of features. The array will either contain the topmost feature * when a hit was detected, or it will be empty. * * The hit detection algorithm used for this method is optimized for performance, but is less * accurate than the one used in [map.getFeaturesAtPixel()]{@link import("../Map.js").default#getFeaturesAtPixel}. * Text is not considered, and icons are only represented by their bounding box instead of the exact * image. * * @param {import("../pixel.js").Pixel} pixel Pixel. * @return {Promise>} Promise that resolves with an array of features. * @api * @override */ getFeatures(pixel) { return super.getFeatures(pixel); } /** * Get features whose bounding box intersects the provided extent. Only features for cached * tiles for the last rendered zoom level are available in the source. So this method is only * suitable for requesting tiles for extents that are currently rendered. * * Features are returned in random tile order and as they are included in the tiles. This means * they can be clipped, duplicated across tiles, and simplified to the render resolution. * * @param {import("../extent.js").Extent} extent Extent. * @return {Array} Features. * @api */ getFeaturesInExtent(extent) { return ( /** @type {Array} */ /** @type {*} */ this.getRenderer().getFeaturesInExtent(extent) ); } /** * @return {VectorTileRenderType} The render mode. */ getRenderMode() { return this.renderMode_; } /** * Return the level as number to which we will preload tiles up to. * @return {number} The level to preload tiles up to. * @observable * @api */ getPreload() { return ( /** @type {number} */ this.get(TileProperty_default.PRELOAD) ); } /** * Deprecated. Whether we use interim tiles on error. * @return {boolean} Use interim tiles on error. * @observable * @api */ getUseInterimTilesOnError() { return ( /** @type {boolean} */ this.get(TileProperty_default.USE_INTERIM_TILES_ON_ERROR) ); } /** * Set the level as number to which we will preload tiles up to. * @param {number} preload The level to preload tiles up to. * @observable * @api */ setPreload(preload) { this.set(TileProperty_default.PRELOAD, preload); } /** * Deprecated. Set whether we use interim tiles on error. * @param {boolean} useInterimTilesOnError Use interim tiles on error. * @observable * @api */ setUseInterimTilesOnError(useInterimTilesOnError) { this.set(TileProperty_default.USE_INTERIM_TILES_ON_ERROR, useInterimTilesOnError); } }; var VectorTile_default = VectorTileLayer; // node_modules/ol/webgl.js var ARRAY_BUFFER = 34962; var ELEMENT_ARRAY_BUFFER = 34963; var STREAM_DRAW = 35040; var STATIC_DRAW = 35044; var DYNAMIC_DRAW = 35048; var UNSIGNED_BYTE = 5121; var UNSIGNED_SHORT = 5123; var UNSIGNED_INT = 5125; var FLOAT = 5126; var CONTEXT_IDS = ["experimental-webgl", "webgl", "webkit-3d", "moz-webgl"]; function getContext(canvas, attributes) { attributes = Object.assign( { preserveDrawingBuffer: true, antialias: SAFARI_BUG_237906 ? false : true // https://bugs.webkit.org/show_bug.cgi?id=237906 }, attributes ); const ii = CONTEXT_IDS.length; for (let i = 0; i < ii; ++i) { try { const context = canvas.getContext(CONTEXT_IDS[i], attributes); if (context) { return ( /** @type {!WebGLRenderingContext} */ context ); } } catch { } } return null; } // node_modules/ol/webgl/Buffer.js var BufferUsage = { STATIC_DRAW, STREAM_DRAW, DYNAMIC_DRAW }; var WebGLArrayBuffer = class { /** * @param {number} type Buffer type, either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER. * @param {number} [usage] Intended usage, either `STATIC_DRAW`, `STREAM_DRAW` or `DYNAMIC_DRAW`. * Default is `STATIC_DRAW`. */ constructor(type, usage) { this.array_ = null; this.type_ = type; assert( type === ARRAY_BUFFER || type === ELEMENT_ARRAY_BUFFER, "A `WebGLArrayBuffer` must either be of type `ELEMENT_ARRAY_BUFFER` or `ARRAY_BUFFER`" ); this.usage_ = usage !== void 0 ? usage : BufferUsage.STATIC_DRAW; } /** * Populates the buffer with an array of the given size (all values will be zeroes). * @param {number} size Array size * @return {WebGLArrayBuffer} This */ ofSize(size) { this.array_ = new (getArrayClassForType(this.type_))(size); return this; } /** * Populates the buffer with an array of the given size. * @param {Array} array Numerical array * @return {WebGLArrayBuffer} This */ fromArray(array) { this.array_ = getArrayClassForType(this.type_).from(array); return this; } /** * Populates the buffer with a raw binary array buffer. * @param {ArrayBuffer} buffer Raw binary buffer to populate the array with. Note that this buffer must have been * initialized for the same typed array class. * @return {WebGLArrayBuffer} This */ fromArrayBuffer(buffer2) { this.array_ = new (getArrayClassForType(this.type_))(buffer2); return this; } /** * @return {number} Buffer type. */ getType() { return this.type_; } /** * Will return null if the buffer was not initialized * @return {Float32Array|Uint32Array|null} Array. */ getArray() { return this.array_; } /** * @param {Float32Array|Uint32Array} array Array. */ setArray(array) { const ArrayType = getArrayClassForType(this.type_); if (!(array instanceof ArrayType)) { throw new Error(`Expected ${ArrayType}`); } this.array_ = array; } /** * @return {number} Usage. */ getUsage() { return this.usage_; } /** * Will return 0 if the buffer is not initialized * @return {number} Array size */ getSize() { return this.array_ ? this.array_.length : 0; } }; function getArrayClassForType(type) { switch (type) { case ARRAY_BUFFER: return Float32Array; case ELEMENT_ARRAY_BUFFER: return Uint32Array; default: return Float32Array; } } var Buffer_default = WebGLArrayBuffer; // node_modules/ol/webgl/ContextEventType.js var ContextEventType_default = { LOST: "webglcontextlost", RESTORED: "webglcontextrestored" }; // node_modules/ol/webgl/PostProcessingPass.js var DEFAULT_VERTEX_SHADER = ` precision mediump float; attribute vec2 a_position; varying vec2 v_texCoord; varying vec2 v_screenCoord; uniform vec2 u_screenSize; void main() { v_texCoord = a_position * 0.5 + 0.5; v_screenCoord = v_texCoord * u_screenSize; gl_Position = vec4(a_position, 0.0, 1.0); } `; var DEFAULT_FRAGMENT_SHADER = ` precision mediump float; uniform sampler2D u_image; uniform float u_opacity; varying vec2 v_texCoord; void main() { gl_FragColor = texture2D(u_image, v_texCoord) * u_opacity; } `; var WebGLPostProcessingPass = class { /** * @param {Options} options Options. */ constructor(options) { this.gl_ = options.webGlContext; const gl = this.gl_; this.scaleRatio_ = options.scaleRatio || 1; this.renderTargetTexture_ = gl.createTexture(); this.renderTargetTextureSize_ = null; this.frameBuffer_ = gl.createFramebuffer(); this.depthBuffer_ = gl.createRenderbuffer(); const vertexShader = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource( vertexShader, options.vertexShader || DEFAULT_VERTEX_SHADER ); gl.compileShader(vertexShader); const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource( fragmentShader, options.fragmentShader || DEFAULT_FRAGMENT_SHADER ); gl.compileShader(fragmentShader); this.renderTargetProgram_ = gl.createProgram(); gl.attachShader(this.renderTargetProgram_, vertexShader); gl.attachShader(this.renderTargetProgram_, fragmentShader); gl.linkProgram(this.renderTargetProgram_); this.renderTargetVerticesBuffer_ = gl.createBuffer(); const verticesArray = [-1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1]; gl.bindBuffer(gl.ARRAY_BUFFER, this.renderTargetVerticesBuffer_); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array(verticesArray), gl.STATIC_DRAW ); this.renderTargetAttribLocation_ = gl.getAttribLocation( this.renderTargetProgram_, "a_position" ); this.renderTargetUniformLocation_ = gl.getUniformLocation( this.renderTargetProgram_, "u_screenSize" ); this.renderTargetOpacityLocation_ = gl.getUniformLocation( this.renderTargetProgram_, "u_opacity" ); this.renderTargetTextureLocation_ = gl.getUniformLocation( this.renderTargetProgram_, "u_image" ); this.uniforms_ = []; options.uniforms && Object.keys(options.uniforms).forEach((name) => { this.uniforms_.push({ value: options.uniforms[name], location: gl.getUniformLocation(this.renderTargetProgram_, name) }); }); } getRenderTargetTexture() { return this.renderTargetTexture_; } /** * Get the WebGL rendering context * @return {WebGLRenderingContext} The rendering context. */ getGL() { return this.gl_; } /** * Initialize the render target texture of the post process, make sure it is at the * right size and bind it as a render target for the next draw calls. * The last step to be initialized will be the one where the primitives are rendered. * @param {import("../Map.js").FrameState} frameState current frame state */ init(frameState) { const gl = this.getGL(); const textureSize = [ gl.drawingBufferWidth * this.scaleRatio_, gl.drawingBufferHeight * this.scaleRatio_ ]; gl.bindFramebuffer(gl.FRAMEBUFFER, this.getFrameBuffer()); gl.bindRenderbuffer(gl.RENDERBUFFER, this.getDepthBuffer()); gl.viewport(0, 0, textureSize[0], textureSize[1]); if (!this.renderTargetTextureSize_ || this.renderTargetTextureSize_[0] !== textureSize[0] || this.renderTargetTextureSize_[1] !== textureSize[1]) { this.renderTargetTextureSize_ = textureSize; const level = 0; const internalFormat = gl.RGBA; const border = 0; const format = gl.RGBA; const type = gl.UNSIGNED_BYTE; const data = null; gl.bindTexture(gl.TEXTURE_2D, this.renderTargetTexture_); gl.texImage2D( gl.TEXTURE_2D, level, internalFormat, textureSize[0], textureSize[1], border, format, type, data ); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.renderTargetTexture_, 0 ); gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, textureSize[0], textureSize[1] ); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depthBuffer_ ); } } /** * Render to the next postprocessing pass (or to the canvas if final pass). * @param {import("../Map.js").FrameState} frameState current frame state * @param {WebGLPostProcessingPass} [nextPass] Next pass, optional * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing. * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing. */ apply(frameState, nextPass, preCompose, postCompose) { const gl = this.getGL(); const size = frameState.size; gl.bindFramebuffer( gl.FRAMEBUFFER, nextPass ? nextPass.getFrameBuffer() : null ); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, this.renderTargetTexture_); if (!nextPass) { const canvasId = getUid(gl.canvas); if (!frameState.renderTargets[canvasId]) { const attributes = gl.getContextAttributes(); if (attributes && attributes.preserveDrawingBuffer) { gl.clearColor(0, 0, 0, 0); gl.clearDepth(1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); } frameState.renderTargets[canvasId] = true; } } gl.disable(gl.DEPTH_TEST); gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.bindBuffer(gl.ARRAY_BUFFER, this.renderTargetVerticesBuffer_); gl.useProgram(this.renderTargetProgram_); gl.enableVertexAttribArray(this.renderTargetAttribLocation_); gl.vertexAttribPointer( this.renderTargetAttribLocation_, 2, gl.FLOAT, false, 0, 0 ); gl.uniform2f(this.renderTargetUniformLocation_, size[0], size[1]); gl.uniform1i(this.renderTargetTextureLocation_, 0); const opacity = frameState.layerStatesArray[frameState.layerIndex].opacity; gl.uniform1f(this.renderTargetOpacityLocation_, opacity); this.applyUniforms(frameState); if (preCompose) { preCompose(gl, frameState); } gl.drawArrays(gl.TRIANGLES, 0, 6); if (postCompose) { postCompose(gl, frameState); } } /** * @return {WebGLFramebuffer} Frame buffer */ getFrameBuffer() { return this.frameBuffer_; } /** * @return {WebGLRenderbuffer} Depth buffer */ getDepthBuffer() { return this.depthBuffer_; } /** * Sets the custom uniforms based on what was given in the constructor. * @param {import("../Map.js").FrameState} frameState Frame state. * @private */ applyUniforms(frameState) { const gl = this.getGL(); let value; let textureSlot = 1; this.uniforms_.forEach(function(uniform) { value = typeof uniform.value === "function" ? uniform.value(frameState) : uniform.value; if (value instanceof HTMLCanvasElement || value instanceof ImageData) { if (!uniform.texture) { uniform.texture = gl.createTexture(); } gl.activeTexture(gl[`TEXTURE${textureSlot}`]); gl.bindTexture(gl.TEXTURE_2D, uniform.texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); if (value instanceof ImageData) { gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, value.width, value.height, 0, gl.UNSIGNED_BYTE, new Uint8Array(value.data) ); } else { gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, value ); } gl.uniform1i(uniform.location, textureSlot++); } else if (Array.isArray(value)) { switch (value.length) { case 2: gl.uniform2f(uniform.location, value[0], value[1]); return; case 3: gl.uniform3f(uniform.location, value[0], value[1], value[2]); return; case 4: gl.uniform4f( uniform.location, value[0], value[1], value[2], value[3] ); return; default: return; } } else if (typeof value === "number") { gl.uniform1f(uniform.location, value); } }); } }; var PostProcessingPass_default = WebGLPostProcessingPass; // node_modules/ol/webgl/Helper.js var DefaultUniform = { PROJECTION_MATRIX: "u_projectionMatrix", SCREEN_TO_WORLD_MATRIX: "u_screenToWorldMatrix", TIME: "u_time", ZOOM: "u_zoom", RESOLUTION: "u_resolution", ROTATION: "u_rotation", VIEWPORT_SIZE_PX: "u_viewportSizePx", PIXEL_RATIO: "u_pixelRatio", HIT_DETECTION: "u_hitDetection" }; var AttributeType = { UNSIGNED_BYTE, UNSIGNED_SHORT, UNSIGNED_INT, FLOAT }; var canvasCache = {}; function getSharedCanvasCacheKey(key) { return "shared/" + key; } var uniqueCanvasCacheKeyCount = 0; function getUniqueCanvasCacheKey() { const key = "unique/" + uniqueCanvasCacheKeyCount; uniqueCanvasCacheKeyCount += 1; return key; } function getOrCreateContext(key) { let cacheItem = canvasCache[key]; if (!cacheItem) { const canvas = document.createElement("canvas"); canvas.width = 1; canvas.height = 1; canvas.style.position = "absolute"; canvas.style.left = "0"; const context = getContext(canvas); cacheItem = { users: 0, context }; canvasCache[key] = cacheItem; } cacheItem.users += 1; return cacheItem.context; } function releaseCanvas(key) { const cacheItem = canvasCache[key]; if (!cacheItem) { return; } cacheItem.users -= 1; if (cacheItem.users > 0) { return; } const gl = cacheItem.context; const extension = gl.getExtension("WEBGL_lose_context"); if (extension) { extension.loseContext(); } const canvas = gl.canvas; canvas.width = 1; canvas.height = 1; delete canvasCache[key]; } var WebGLHelper = class extends Disposable_default { /** * @param {Options} [options] Options. */ constructor(options) { super(); options = options || {}; this.boundHandleWebGLContextLost_ = this.handleWebGLContextLost.bind(this); this.boundHandleWebGLContextRestored_ = this.handleWebGLContextRestored.bind(this); this.canvasCacheKey_ = options.canvasCacheKey ? getSharedCanvasCacheKey(options.canvasCacheKey) : getUniqueCanvasCacheKey(); this.gl_ = getOrCreateContext(this.canvasCacheKey_); this.bufferCache_ = {}; this.extensionCache_ = {}; this.currentProgram_ = null; this.needsToBeRecreated_ = false; const canvas = this.gl_.canvas; canvas.addEventListener( ContextEventType_default.LOST, this.boundHandleWebGLContextLost_ ); canvas.addEventListener( ContextEventType_default.RESTORED, this.boundHandleWebGLContextRestored_ ); this.offsetRotateMatrix_ = create(); this.offsetScaleMatrix_ = create(); this.tmpMat4_ = create2(); this.uniformLocationsByProgram_ = {}; this.attribLocationsByProgram_ = {}; this.uniforms_ = []; if (options.uniforms) { this.setUniforms(options.uniforms); } this.postProcessPasses_ = options.postProcesses ? options.postProcesses.map( (options2) => new PostProcessingPass_default({ webGlContext: this.gl_, scaleRatio: options2.scaleRatio, vertexShader: options2.vertexShader, fragmentShader: options2.fragmentShader, uniforms: options2.uniforms }) ) : [new PostProcessingPass_default({ webGlContext: this.gl_ })]; this.shaderCompileErrors_ = null; this.startTime_ = Date.now(); this.maxAttributeCount_ = this.gl_.getParameter( this.gl_.MAX_VERTEX_ATTRIBS ); } /** * @param {Object} uniforms Uniform definitions. */ setUniforms(uniforms) { this.uniforms_ = []; this.addUniforms(uniforms); } /** * @param {Object} uniforms Uniform definitions. */ addUniforms(uniforms) { for (const name in uniforms) { this.uniforms_.push({ name, value: uniforms[name] }); } } /** * @param {string} canvasCacheKey The canvas cache key. * @return {boolean} The provided key matches the one this helper was constructed with. */ canvasCacheKeyMatches(canvasCacheKey) { return this.canvasCacheKey_ === getSharedCanvasCacheKey(canvasCacheKey); } /** * Get a WebGL extension. If the extension is not supported, null is returned. * Extensions are cached after they are enabled for the first time. * @param {string} name The extension name. * @return {Object|null} The extension or null if not supported. */ getExtension(name) { if (name in this.extensionCache_) { return this.extensionCache_[name]; } const extension = this.gl_.getExtension(name); this.extensionCache_[name] = extension; return extension; } /** * Will throw if the extension is not available * @return {ANGLE_instanced_arrays} Extension */ getInstancedRenderingExtension_() { const ext = this.getExtension("ANGLE_instanced_arrays"); assert( !!ext, "WebGL extension 'ANGLE_instanced_arrays' is required for vector rendering" ); return ext; } /** * Just bind the buffer if it's in the cache. Otherwise create * the WebGL buffer, bind it, populate it, and add an entry to * the cache. * @param {import("./Buffer").default} buffer Buffer. */ bindBuffer(buffer2) { const gl = this.gl_; const bufferKey = getUid(buffer2); let bufferCache = this.bufferCache_[bufferKey]; if (!bufferCache) { const webGlBuffer = gl.createBuffer(); bufferCache = { buffer: buffer2, webGlBuffer }; this.bufferCache_[bufferKey] = bufferCache; } gl.bindBuffer(buffer2.getType(), bufferCache.webGlBuffer); } /** * Update the data contained in the buffer array; this is required for the * new data to be rendered * @param {import("./Buffer").default} buffer Buffer. */ flushBufferData(buffer2) { const gl = this.gl_; this.bindBuffer(buffer2); gl.bufferData(buffer2.getType(), buffer2.getArray(), buffer2.getUsage()); } /** * @param {import("./Buffer.js").default} buf Buffer. */ deleteBuffer(buf) { const bufferKey = getUid(buf); delete this.bufferCache_[bufferKey]; } /** * Clean up. * @override */ disposeInternal() { const canvas = this.gl_.canvas; canvas.removeEventListener( ContextEventType_default.LOST, this.boundHandleWebGLContextLost_ ); canvas.removeEventListener( ContextEventType_default.RESTORED, this.boundHandleWebGLContextRestored_ ); releaseCanvas(this.canvasCacheKey_); delete this.gl_; } /** * Clear the buffer & set the viewport to draw. * Post process passes will be initialized here, the first one being bound as a render target for * subsequent draw calls. * @param {import("../Map.js").FrameState} frameState current frame state * @param {boolean} [disableAlphaBlend] If true, no alpha blending will happen. * @param {boolean} [enableDepth] If true, enables depth testing. */ prepareDraw(frameState, disableAlphaBlend, enableDepth) { const gl = this.gl_; const canvas = this.getCanvas(); const size = frameState.size; const pixelRatio = frameState.pixelRatio; if (canvas.width !== size[0] * pixelRatio || canvas.height !== size[1] * pixelRatio) { canvas.width = size[0] * pixelRatio; canvas.height = size[1] * pixelRatio; canvas.style.width = size[0] + "px"; canvas.style.height = size[1] + "px"; } for (let i = this.postProcessPasses_.length - 1; i >= 0; i--) { this.postProcessPasses_[i].init(frameState); } gl.bindTexture(gl.TEXTURE_2D, null); gl.clearColor(0, 0, 0, 0); gl.depthRange(0, 1); gl.clearDepth(1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA); if (enableDepth) { gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); } else { gl.disable(gl.DEPTH_TEST); } } /** * @param {WebGLFramebuffer|null} frameBuffer The frame buffer. * @param {WebGLTexture} [texture] The texture. */ bindFrameBuffer(frameBuffer, texture) { const gl = this.getGL(); gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer); if (texture) { gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0 ); } } /** * Bind the frame buffer from the initial render. */ bindInitialFrameBuffer() { const gl = this.getGL(); const frameBuffer = this.postProcessPasses_[0].getFrameBuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer); const texture = this.postProcessPasses_[0].getRenderTargetTexture(); gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0 ); } /** * Prepare a program to use a texture. * @param {WebGLTexture} texture The texture. * @param {number} slot The texture slot. * @param {string} uniformName The corresponding uniform name. */ bindTexture(texture, slot, uniformName) { const gl = this.gl_; gl.activeTexture(gl.TEXTURE0 + slot); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(this.getUniformLocation(uniformName), slot); } /** * Set up an attribute array buffer for use in the vertex shader. * @param {import("./Buffer").default} buffer The buffer. * @param {string} attributeName The attribute name. * @param {number} size The number of components per attribute vertex. */ bindAttribute(buffer2, attributeName, size) { const gl = this.getGL(); this.bindBuffer(buffer2); const index = this.getAttributeLocation(attributeName); gl.enableVertexAttribArray(index); gl.vertexAttribPointer(index, size, gl.FLOAT, false, 0, 0); } /** * Clear the render target & bind it for future draw operations. * This is similar to `prepareDraw`, only post processes will not be applied. * Note: the whole viewport will be drawn to the render target, regardless of its size. * @param {import("../Map.js").FrameState} frameState current frame state * @param {import("./RenderTarget.js").default} renderTarget Render target to draw to * @param {boolean} [disableAlphaBlend] If true, no alpha blending will happen. * @param {boolean} [enableDepth] If true, enables depth testing. */ prepareDrawToRenderTarget(frameState, renderTarget, disableAlphaBlend, enableDepth) { const gl = this.gl_; const size = renderTarget.getSize(); gl.bindFramebuffer(gl.FRAMEBUFFER, renderTarget.getFramebuffer()); gl.bindRenderbuffer(gl.RENDERBUFFER, renderTarget.getDepthbuffer()); gl.viewport(0, 0, size[0], size[1]); gl.bindTexture(gl.TEXTURE_2D, renderTarget.getTexture()); gl.clearColor(0, 0, 0, 0); gl.depthRange(0, 1); gl.clearDepth(1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); gl.enable(gl.BLEND); gl.blendFunc(gl.ONE, disableAlphaBlend ? gl.ZERO : gl.ONE_MINUS_SRC_ALPHA); if (enableDepth) { gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); } else { gl.disable(gl.DEPTH_TEST); } } /** * Execute a draw call based on the currently bound program, texture, buffers, attributes. * @param {number} start Start index. * @param {number} end End index. */ drawElements(start, end) { const gl = this.gl_; this.getExtension("OES_element_index_uint"); const elementType = gl.UNSIGNED_INT; const elementSize = 4; const numItems = end - start; const offsetInBytes = start * elementSize; gl.drawElements(gl.TRIANGLES, numItems, elementType, offsetInBytes); } /** * Execute a draw call similar to `drawElements`, but using instanced rendering. * Will have no effect if `enableAttributesInstanced` was not called for this rendering pass. * @param {number} start Start index. * @param {number} end End index. * @param {number} instanceCount The number of instances to render */ drawElementsInstanced(start, end, instanceCount) { const gl = this.gl_; this.getExtension("OES_element_index_uint"); const ext = this.getInstancedRenderingExtension_(); const elementType = gl.UNSIGNED_INT; const elementSize = 4; const numItems = end - start; const offsetInBytes = start * elementSize; ext.drawElementsInstancedANGLE( gl.TRIANGLES, numItems, elementType, offsetInBytes, instanceCount ); for (let i = 0; i < this.maxAttributeCount_; i++) { ext.vertexAttribDivisorANGLE(i, 0); } } /** * Apply the successive post process passes which will eventually render to the actual canvas. * @param {import("../Map.js").FrameState} frameState current frame state * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [preCompose] Called before composing. * @param {function(WebGLRenderingContext, import("../Map.js").FrameState):void} [postCompose] Called before composing. */ finalizeDraw(frameState, preCompose, postCompose) { for (let i = 0, ii = this.postProcessPasses_.length; i < ii; i++) { if (i === ii - 1) { this.postProcessPasses_[i].apply( frameState, null, preCompose, postCompose ); } else { this.postProcessPasses_[i].apply( frameState, this.postProcessPasses_[i + 1] ); } } } /** * @return {HTMLCanvasElement} Canvas. */ getCanvas() { return ( /** @type {HTMLCanvasElement} */ this.gl_.canvas ); } /** * Get the WebGL rendering context * @return {WebGLRenderingContext} The rendering context. */ getGL() { return this.gl_; } /** * Sets the default matrix uniforms for a given frame state. This is called internally in `prepareDraw`. * @param {import("../Map.js").FrameState} frameState Frame state. */ applyFrameState(frameState) { const size = frameState.size; const rotation = frameState.viewState.rotation; const pixelRatio = frameState.pixelRatio; this.setUniformFloatValue( DefaultUniform.TIME, (Date.now() - this.startTime_) * 1e-3 ); this.setUniformFloatValue(DefaultUniform.ZOOM, frameState.viewState.zoom); this.setUniformFloatValue( DefaultUniform.RESOLUTION, frameState.viewState.resolution ); this.setUniformFloatValue(DefaultUniform.PIXEL_RATIO, pixelRatio); this.setUniformFloatVec2(DefaultUniform.VIEWPORT_SIZE_PX, [ size[0], size[1] ]); this.setUniformFloatValue(DefaultUniform.ROTATION, rotation); } /** * Sets the `u_hitDetection` uniform. * @param {boolean} enabled Whether to enable the hit detection code path */ applyHitDetectionUniform(enabled) { const loc = this.getUniformLocation(DefaultUniform.HIT_DETECTION); this.getGL().uniform1i(loc, enabled ? 1 : 0); if (enabled) { this.setUniformFloatValue(DefaultUniform.PIXEL_RATIO, 0.5); } } /** * Sets the custom uniforms based on what was given in the constructor. This is called internally in `prepareDraw`. * @param {import("../Map.js").FrameState} frameState Frame state. */ applyUniforms(frameState) { const gl = this.gl_; let value; let textureSlot = 0; this.uniforms_.forEach((uniform) => { value = typeof uniform.value === "function" ? uniform.value(frameState) : uniform.value; if (value instanceof HTMLCanvasElement || value instanceof HTMLImageElement || value instanceof ImageData || value instanceof WebGLTexture) { if (value instanceof WebGLTexture && !uniform.texture) { uniform.prevValue = void 0; uniform.texture = value; } else if (!uniform.texture) { uniform.prevValue = void 0; uniform.texture = gl.createTexture(); } this.bindTexture(uniform.texture, textureSlot, uniform.name); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); const imageReady = !(value instanceof HTMLImageElement) || /** @type {HTMLImageElement} */ value.complete; if (!(value instanceof WebGLTexture) && imageReady && uniform.prevValue !== value) { uniform.prevValue = value; gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, value ); } textureSlot++; } else if (Array.isArray(value) && value.length === 6) { this.setUniformMatrixValue( uniform.name, fromTransform(this.tmpMat4_, value) ); } else if (Array.isArray(value) && value.length <= 4) { switch (value.length) { case 2: gl.uniform2f( this.getUniformLocation(uniform.name), value[0], value[1] ); return; case 3: gl.uniform3f( this.getUniformLocation(uniform.name), value[0], value[1], value[2] ); return; case 4: gl.uniform4f( this.getUniformLocation(uniform.name), value[0], value[1], value[2], value[3] ); return; default: return; } } else if (typeof value === "number") { gl.uniform1f(this.getUniformLocation(uniform.name), value); } }); } /** * Set up a program for use. The program will be set as the current one. Then, the uniforms used * in the program will be set based on the current frame state and the helper configuration. * @param {WebGLProgram} program Program. * @param {import("../Map.js").FrameState} [frameState] Frame state. */ useProgram(program, frameState) { this.disableAllAttributes_(); const gl = this.gl_; gl.useProgram(program); this.currentProgram_ = program; if (frameState) { this.applyFrameState(frameState); this.applyUniforms(frameState); } } /** * Will attempt to compile a vertex or fragment shader based on source * On error, the shader will be returned but * `gl.getShaderParameter(shader, gl.COMPILE_STATUS)` will return `true` * Use `gl.getShaderInfoLog(shader)` to have details * @param {string} source Shader source * @param {ShaderType} type VERTEX_SHADER or FRAGMENT_SHADER * @return {WebGLShader} Shader object */ compileShader(source, type) { const gl = this.gl_; const shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); return shader; } /** * Create a program for a vertex and fragment shader. Throws if shader compilation fails. * @param {string} fragmentShaderSource Fragment shader source. * @param {string} vertexShaderSource Vertex shader source. * @return {WebGLProgram} Program */ getProgram(fragmentShaderSource, vertexShaderSource) { const gl = this.gl_; const fragmentShader = this.compileShader( fragmentShaderSource, gl.FRAGMENT_SHADER ); const vertexShader = this.compileShader( vertexShaderSource, gl.VERTEX_SHADER ); const program = gl.createProgram(); gl.attachShader(program, fragmentShader); gl.attachShader(program, vertexShader); gl.linkProgram(program); if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) { const message = `Fragment shader compilation failed: ${gl.getShaderInfoLog( fragmentShader )}`; throw new Error(message); } gl.deleteShader(fragmentShader); if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) { const message = `Vertex shader compilation failed: ${gl.getShaderInfoLog( vertexShader )}`; throw new Error(message); } gl.deleteShader(vertexShader); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { const message = `GL program linking failed: ${gl.getProgramInfoLog( program )}`; throw new Error(message); } return program; } /** * Will get the location from the shader or the cache * @param {string} name Uniform name * @return {WebGLUniformLocation} uniformLocation */ getUniformLocation(name) { const programUid = getUid(this.currentProgram_); if (this.uniformLocationsByProgram_[programUid] === void 0) { this.uniformLocationsByProgram_[programUid] = {}; } if (this.uniformLocationsByProgram_[programUid][name] === void 0) { this.uniformLocationsByProgram_[programUid][name] = this.gl_.getUniformLocation(this.currentProgram_, name); } return this.uniformLocationsByProgram_[programUid][name]; } /** * Will get the location from the shader or the cache * @param {string} name Attribute name * @return {number} attribLocation */ getAttributeLocation(name) { const programUid = getUid(this.currentProgram_); if (this.attribLocationsByProgram_[programUid] === void 0) { this.attribLocationsByProgram_[programUid] = {}; } if (this.attribLocationsByProgram_[programUid][name] === void 0) { this.attribLocationsByProgram_[programUid][name] = this.gl_.getAttribLocation(this.currentProgram_, name); } return this.attribLocationsByProgram_[programUid][name]; } /** * Sets the given transform to apply the rotation/translation/scaling of the given frame state. * The resulting transform can be used to convert world space coordinates to view coordinates in the [-1, 1] range. * @param {import("../Map.js").FrameState} frameState Frame state. * @param {import("../transform").Transform} transform Transform to update. * @return {import("../transform").Transform} The updated transform object. */ makeProjectionTransform(frameState, transform) { const size = frameState.size; const rotation = frameState.viewState.rotation; const resolution = frameState.viewState.resolution; const center = frameState.viewState.center; compose( transform, 0, 0, 2 / (resolution * size[0]), 2 / (resolution * size[1]), -rotation, -center[0], -center[1] ); return transform; } /** * Give a value for a standard float uniform * @param {string} uniform Uniform name * @param {number} value Value */ setUniformFloatValue(uniform, value) { this.gl_.uniform1f(this.getUniformLocation(uniform), value); } /** * Give a value for a vec2 uniform * @param {string} uniform Uniform name * @param {Array} value Array of length 4. */ setUniformFloatVec2(uniform, value) { this.gl_.uniform2fv(this.getUniformLocation(uniform), value); } /** * Give a value for a vec4 uniform * @param {string} uniform Uniform name * @param {Array} value Array of length 4. */ setUniformFloatVec4(uniform, value) { this.gl_.uniform4fv(this.getUniformLocation(uniform), value); } /** * Give a value for a standard matrix4 uniform * @param {string} uniform Uniform name * @param {Array} value Matrix value */ setUniformMatrixValue(uniform, value) { this.gl_.uniformMatrix4fv(this.getUniformLocation(uniform), false, value); } /** * Disable all vertex attributes. * @private */ disableAllAttributes_() { for (let i = 0; i < this.maxAttributeCount_; i++) { this.gl_.disableVertexAttribArray(i); } } /** * Will set the currently bound buffer to an attribute of the shader program. Used by `#enableAttributes` * internally. * @param {string} attribName Attribute name * @param {number} size Number of components per attributes * @param {number} type UNSIGNED_INT, UNSIGNED_BYTE, UNSIGNED_SHORT or FLOAT * @param {number} stride Stride in bytes (0 means attribs are packed) * @param {number} offset Offset in bytes * @param {boolean} instanced Whether the attribute is used for instanced rendering * @private */ enableAttributeArray_(attribName, size, type, stride, offset, instanced) { const location = this.getAttributeLocation(attribName); if (location < 0) { return; } this.gl_.enableVertexAttribArray(location); this.gl_.vertexAttribPointer(location, size, type, false, stride, offset); if (instanced) { this.getInstancedRenderingExtension_().vertexAttribDivisorANGLE( location, 1 ); } } /** * @private * @param {Array} attributes Ordered list of attributes to read from the buffer * @param {boolean} instanced Whether the attributes are instanced. */ enableAttributes_(attributes, instanced) { const stride = computeAttributesStride(attributes); let offset = 0; for (let i = 0; i < attributes.length; i++) { const attr = attributes[i]; if (attr.name) { this.enableAttributeArray_( attr.name, attr.size, attr.type || FLOAT, stride, offset, instanced ); } offset += attr.size * getByteSizeFromType(attr.type); } } /** * Will enable the following attributes to be read from the currently bound buffer, * i.e. tell the GPU where to read the different attributes in the buffer. An error in the * size/type/order of attributes will most likely break the rendering and throw a WebGL exception. * @param {Array} attributes Ordered list of attributes to read from the buffer */ enableAttributes(attributes) { this.enableAttributes_(attributes, false); } /** * Will enable these attributes as instanced, meaning that they will only be read * once per instance instead of per vertex. * @param {Array} attributes Ordered list of attributes to read from the buffer */ enableAttributesInstanced(attributes) { this.enableAttributes_(attributes, true); } /** * WebGL context was lost * @param {WebGLContextEvent} event The context loss event. * @private */ handleWebGLContextLost(event) { clear(this.bufferCache_); this.currentProgram_ = null; event.preventDefault(); } /** * WebGL context was restored * @private */ handleWebGLContextRestored() { this.needsToBeRecreated_ = true; } /** * Returns whether this helper needs to be recreated, as the context was lost and then restored. * @return {boolean} Whether this helper needs to be recreated. */ needsToBeRecreated() { return this.needsToBeRecreated_; } /** * Will create or reuse a given webgl texture and apply the given size. If no image data * specified, the texture will be empty, otherwise image data will be used and the `size` * parameter will be ignored. If a Uint8Array is provided for data, a size must also be provided. * Note: wrap parameters are set to clamp to edge, min filter is set to linear. * @param {Array} size Expected size of the texture * @param {ImageData|HTMLImageElement|HTMLCanvasElement|Uint8Array|null} data Image data/object to bind to the texture * @param {WebGLTexture} [texture] Existing texture to reuse * @param {boolean} [nearest] Use gl.NEAREST for min/mag filter. * @return {WebGLTexture} The generated texture */ createTexture(size, data, texture, nearest) { const gl = this.gl_; texture = texture || gl.createTexture(); const filter = nearest ? gl.NEAREST : gl.LINEAR; gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); const level = 0; const internalFormat = gl.RGBA; const border = 0; const format = gl.RGBA; const type = gl.UNSIGNED_BYTE; if (data instanceof Uint8Array) { gl.texImage2D( gl.TEXTURE_2D, level, internalFormat, size[0], size[1], border, format, type, data ); } else if (data) { gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, format, type, data); } else { gl.texImage2D( gl.TEXTURE_2D, level, internalFormat, size[0], size[1], border, format, type, null ); } return texture; } }; function computeAttributesStride(attributes) { let stride = 0; for (let i = 0; i < attributes.length; i++) { const attr = attributes[i]; stride += attr.size * getByteSizeFromType(attr.type); } return stride; } function getByteSizeFromType(type) { switch (type) { case AttributeType.UNSIGNED_BYTE: return Uint8Array.BYTES_PER_ELEMENT; case AttributeType.UNSIGNED_SHORT: return Uint16Array.BYTES_PER_ELEMENT; case AttributeType.UNSIGNED_INT: return Uint32Array.BYTES_PER_ELEMENT; case AttributeType.FLOAT: default: return Float32Array.BYTES_PER_ELEMENT; } } var Helper_default = WebGLHelper; // node_modules/ol/webgl/BaseTileRepresentation.js var BaseTileRepresentation = class extends Target_default { /** * @param {TileRepresentationOptions} options The tile representation options. */ constructor(options) { super(); this.tile; this.handleTileChange_ = this.handleTileChange_.bind(this); this.gutter = options.gutter || 0; this.helper = options.helper; this.loaded = false; this.ready = false; } /** * @param {TileType} tile Tile. */ setTile(tile) { if (tile !== this.tile) { if (this.tile) { this.tile.removeEventListener(EventType_default.CHANGE, this.handleTileChange_); } this.tile = tile; this.loaded = tile.getState() === TileState_default.LOADED; if (this.loaded) { this.uploadTile(); } else { if (tile instanceof ImageTile_default) { const image = tile.getImage(); if (image instanceof Image && !image.crossOrigin) { image.crossOrigin = "anonymous"; } } tile.addEventListener(EventType_default.CHANGE, this.handleTileChange_); } } } /** * @abstract * @protected */ uploadTile() { abstract(); } setReady() { this.ready = true; this.dispatchEvent(EventType_default.CHANGE); } handleTileChange_() { if (this.tile.getState() === TileState_default.LOADED) { this.loaded = true; this.uploadTile(); } } /** * @param {import("./Helper.js").default} helper The WebGL helper. */ setHelper(helper) { this.helper = helper; if (this.helper && this.loaded) { this.uploadTile(); } } /** * @override */ disposeInternal() { this.setHelper(null); this.tile.removeEventListener(EventType_default.CHANGE, this.handleTileChange_); } }; var BaseTileRepresentation_default = BaseTileRepresentation; // node_modules/ol/webgl/TileTexture.js function bindAndConfigure(gl, texture, interpolate) { const resampleFilter = interpolate ? gl.LINEAR : gl.NEAREST; gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, resampleFilter); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, resampleFilter); } function uploadImageTexture(gl, texture, image, interpolate) { bindAndConfigure(gl, texture, interpolate); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); } function uploadDataTexture(helper, texture, data, size, bandCount, interpolate) { const gl = helper.getGL(); let textureType; let canInterpolate; if (data instanceof Float32Array) { textureType = gl.FLOAT; helper.getExtension("OES_texture_float"); const extension = helper.getExtension("OES_texture_float_linear"); canInterpolate = extension !== null; } else { textureType = gl.UNSIGNED_BYTE; canInterpolate = true; } bindAndConfigure(gl, texture, interpolate && canInterpolate); const bytesPerRow = data.byteLength / size[1]; let unpackAlignment = 1; if (bytesPerRow % 8 === 0) { unpackAlignment = 8; } else if (bytesPerRow % 4 === 0) { unpackAlignment = 4; } else if (bytesPerRow % 2 === 0) { unpackAlignment = 2; } let format; switch (bandCount) { case 1: { format = gl.LUMINANCE; break; } case 2: { format = gl.LUMINANCE_ALPHA; break; } case 3: { format = gl.RGB; break; } case 4: { format = gl.RGBA; break; } default: { throw new Error(`Unsupported number of bands: ${bandCount}`); } } const oldUnpackAlignment = gl.getParameter(gl.UNPACK_ALIGNMENT); gl.pixelStorei(gl.UNPACK_ALIGNMENT, unpackAlignment); gl.texImage2D( gl.TEXTURE_2D, 0, format, size[0], size[1], 0, format, textureType, data ); gl.pixelStorei(gl.UNPACK_ALIGNMENT, oldUnpackAlignment); } var pixelContext = null; function createPixelContext() { pixelContext = createCanvasContext2D(1, 1, void 0, { willReadFrequently: true }); } var TileTexture = class extends BaseTileRepresentation_default { /** * @param {import("./BaseTileRepresentation.js").TileRepresentationOptions} options The tile texture options. */ constructor(options) { super(options); this.textures = []; this.renderSize_ = toSize( options.grid.getTileSize(options.tile.tileCoord[0]) ); this.bandCount = NaN; const coords = new Buffer_default(ARRAY_BUFFER, STATIC_DRAW); coords.fromArray([ 0, // P0 1, 1, // P1 1, 1, // P2 0, 0, // P3 0 ]); this.helper.flushBufferData(coords); this.coords = coords; this.setTile(options.tile); } /** * @override * @param {import("./Helper.js").default} helper The WebGL helper. */ setHelper(helper) { var _a; const gl = (_a = this.helper) == null ? void 0 : _a.getGL(); if (gl) { this.helper.deleteBuffer(this.coords); for (let i = 0; i < this.textures.length; ++i) { gl.deleteTexture(this.textures[i]); } } super.setHelper(helper); if (helper) { helper.flushBufferData(this.coords); } } /** * @override */ uploadTile() { const helper = this.helper; const gl = helper.getGL(); const tile = this.tile; this.textures.length = 0; let data; if (tile instanceof ImageTile_default || tile instanceof Tile_default) { data = tile.getImage(); } else { data = tile.getData(); } const image = asImageLike(data); if (image) { const texture = gl.createTexture(); this.textures.push(texture); this.bandCount = 4; uploadImageTexture(gl, texture, image, tile.interpolate); this.setReady(); return; } data = asArrayLike(data); const sourceTileSize = ( /** @type {DataTile} */ tile.getSize() ); const pixelSize = [ sourceTileSize[0] + 2 * this.gutter, sourceTileSize[1] + 2 * this.gutter ]; const isFloat = data instanceof Float32Array; const pixelCount = pixelSize[0] * pixelSize[1]; const DataType = isFloat ? Float32Array : Uint8Array; const bytesPerElement = DataType.BYTES_PER_ELEMENT; const bytesPerRow = data.byteLength / pixelSize[1]; this.bandCount = Math.floor(bytesPerRow / bytesPerElement / pixelSize[0]); const textureCount = Math.ceil(this.bandCount / 4); if (textureCount === 1) { const texture = gl.createTexture(); this.textures.push(texture); uploadDataTexture( helper, texture, data, pixelSize, this.bandCount, tile.interpolate ); this.setReady(); return; } const textureDataArrays = new Array(textureCount); for (let textureIndex = 0; textureIndex < textureCount; ++textureIndex) { const texture = gl.createTexture(); this.textures.push(texture); const bandCount = textureIndex < textureCount - 1 ? 4 : (this.bandCount - 1) % 4 + 1; textureDataArrays[textureIndex] = new DataType(pixelCount * bandCount); } let dataIndex = 0; let rowOffset = 0; const colCount = pixelSize[0] * this.bandCount; for (let rowIndex = 0; rowIndex < pixelSize[1]; ++rowIndex) { for (let colIndex = 0; colIndex < colCount; ++colIndex) { const dataValue = data[rowOffset + colIndex]; const pixelIndex = Math.floor(dataIndex / this.bandCount); const bandIndex = colIndex % this.bandCount; const textureIndex = Math.floor(bandIndex / 4); const textureData = textureDataArrays[textureIndex]; const bandCount = textureData.length / pixelCount; const textureBandIndex = bandIndex % 4; textureData[pixelIndex * bandCount + textureBandIndex] = dataValue; ++dataIndex; } rowOffset += bytesPerRow / bytesPerElement; } for (let textureIndex = 0; textureIndex < textureCount; ++textureIndex) { const texture = this.textures[textureIndex]; const textureData = textureDataArrays[textureIndex]; const bandCount = textureData.length / pixelCount; uploadDataTexture( helper, texture, textureData, pixelSize, bandCount, tile.interpolate ); } this.setReady(); } /** * @param {import("../DataTile.js").ImageLike} image The image. * @param {number} renderCol The column index (in rendered tile space). * @param {number} renderRow The row index (in rendered tile space). * @return {Uint8ClampedArray|null} The data. * @private */ getImagePixelData_(image, renderCol, renderRow) { const gutter = this.gutter; const renderWidth = this.renderSize_[0]; const renderHeight = this.renderSize_[1]; if (!pixelContext) { createPixelContext(); } pixelContext.clearRect(0, 0, 1, 1); const sourceWidth = image.width; const sourceHeight = image.height; const sourceWidthWithoutGutter = sourceWidth - 2 * gutter; const sourceHeightWithoutGutter = sourceHeight - 2 * gutter; const sourceCol = gutter + Math.floor(sourceWidthWithoutGutter * (renderCol / renderWidth)); const sourceRow = gutter + Math.floor(sourceHeightWithoutGutter * (renderRow / renderHeight)); let data; try { pixelContext.drawImage(image, sourceCol, sourceRow, 1, 1, 0, 0, 1, 1); data = pixelContext.getImageData(0, 0, 1, 1).data; } catch { pixelContext = null; return null; } return data; } /** * @param {import("../DataTile.js").ArrayLike} data The data. * @param {import("../size.js").Size} sourceSize The size. * @param {number} renderCol The column index (in rendered tile space). * @param {number} renderRow The row index (in rendered tile space). * @return {import("../DataTile.js").ArrayLike|null} The data. * @private */ getArrayPixelData_(data, sourceSize, renderCol, renderRow) { const gutter = this.gutter; const renderWidth = this.renderSize_[0]; const renderHeight = this.renderSize_[1]; const sourceWidthWithoutGutter = sourceSize[0]; const sourceHeightWithoutGutter = sourceSize[1]; const sourceWidth = sourceWidthWithoutGutter + 2 * gutter; const sourceHeight = sourceHeightWithoutGutter + 2 * gutter; const sourceCol = gutter + Math.floor(sourceWidthWithoutGutter * (renderCol / renderWidth)); const sourceRow = gutter + Math.floor(sourceHeightWithoutGutter * (renderRow / renderHeight)); if (data instanceof DataView) { const bytesPerPixel = data.byteLength / (sourceWidth * sourceHeight); const offset2 = bytesPerPixel * (sourceRow * sourceWidth + sourceCol); const buffer2 = data.buffer.slice(offset2, offset2 + bytesPerPixel); return new DataView(buffer2); } const offset = this.bandCount * (sourceRow * sourceWidth + sourceCol); return data.slice(offset, offset + this.bandCount); } /** * Get data for a pixel. If the tile is not loaded, null is returned. * @param {number} renderCol The column index (in rendered tile space). * @param {number} renderRow The row index (in rendered tile space). * @return {import("../DataTile.js").ArrayLike|null} The data. */ getPixelData(renderCol, renderRow) { if (!this.loaded) { return null; } if (this.tile instanceof DataTile_default) { const data = this.tile.getData(); const arrayData = asArrayLike(data); if (arrayData) { const sourceSize = this.tile.getSize(); return this.getArrayPixelData_( arrayData, sourceSize, renderCol, renderRow ); } return this.getImagePixelData_(asImageLike(data), renderCol, renderRow); } return this.getImagePixelData_(this.tile.getImage(), renderCol, renderRow); } }; var TileTexture_default = TileTexture; // node_modules/ol/renderer/webgl/Layer.js var WebGLLayerRenderer = class _WebGLLayerRenderer extends Layer_default { /** * @param {LayerType} layer Layer. * @param {Options} [options] Options. */ constructor(layer, options) { super(layer); options = options || {}; this.inversePixelTransform_ = create(); this.postProcesses_ = options.postProcesses; this.uniforms_ = options.uniforms; this.helper; this.onMapChanged_ = () => { this.clearCache(); this.removeHelper(); }; layer.addChangeListener(Property_default.MAP, this.onMapChanged_); this.dispatchPreComposeEvent = this.dispatchPreComposeEvent.bind(this); this.dispatchPostComposeEvent = this.dispatchPostComposeEvent.bind(this); } /** * @param {WebGLRenderingContext} context The WebGL rendering context. * @param {import("../../Map.js").FrameState} frameState Frame state. * @protected */ dispatchPreComposeEvent(context, frameState) { const layer = this.getLayer(); if (layer.hasListener(EventType_default2.PRECOMPOSE)) { const event = new Event_default( EventType_default2.PRECOMPOSE, void 0, frameState, context ); layer.dispatchEvent(event); } } /** * @param {WebGLRenderingContext} context The WebGL rendering context. * @param {import("../../Map.js").FrameState} frameState Frame state. * @protected */ dispatchPostComposeEvent(context, frameState) { const layer = this.getLayer(); if (layer.hasListener(EventType_default2.POSTCOMPOSE)) { const event = new Event_default( EventType_default2.POSTCOMPOSE, void 0, frameState, context ); layer.dispatchEvent(event); } } /** * Reset options (only handles uniforms). * @param {Options} options Options. */ reset(options) { this.uniforms_ = options.uniforms; if (this.helper) { this.helper.setUniforms(this.uniforms_); } } /** * @protected */ removeHelper() { if (this.helper) { this.helper.dispose(); delete this.helper; } } /** * Determine whether renderFrame should be called. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {boolean} Layer is ready to be rendered. * @override */ prepareFrame(frameState) { if (this.getLayer().getRenderSource()) { let incrementGroup = true; let groupNumber = -1; let className; for (let i = 0, ii = frameState.layerStatesArray.length; i < ii; i++) { const layer = frameState.layerStatesArray[i].layer; const renderer = layer.getRenderer(); if (!(renderer instanceof _WebGLLayerRenderer)) { incrementGroup = true; continue; } const layerClassName = layer.getClassName(); if (incrementGroup || layerClassName !== className) { groupNumber += 1; incrementGroup = false; } className = layerClassName; if (renderer === this) { break; } } const canvasCacheKey = "map/" + frameState.mapId + "/group/" + groupNumber; if (!this.helper || !this.helper.canvasCacheKeyMatches(canvasCacheKey) || this.helper.needsToBeRecreated()) { this.removeHelper(); this.helper = new Helper_default({ postProcesses: this.postProcesses_, uniforms: this.uniforms_, canvasCacheKey }); if (className) { this.helper.getCanvas().className = className; } this.afterHelperCreated(); } } return this.prepareFrameInternal(frameState); } /** * @protected */ afterHelperCreated() { } /** * Determine whether renderFrame should be called. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {boolean} Layer is ready to be rendered. * @protected */ prepareFrameInternal(frameState) { return true; } /** * @protected */ clearCache() { } /** * Clean up. * @override */ disposeInternal() { var _a; this.clearCache(); this.removeHelper(); (_a = this.getLayer()) == null ? void 0 : _a.removeChangeListener( Property_default.MAP, this.onMapChanged_ ); super.disposeInternal(); } /** * @param {import("../../render/EventType.js").default} type Event type. * @param {WebGLRenderingContext} context The rendering context. * @param {import("../../Map.js").FrameState} frameState Frame state. * @private */ dispatchRenderEvent_(type, context, frameState) { const layer = this.getLayer(); if (layer.hasListener(type)) { compose( this.inversePixelTransform_, 0, 0, frameState.pixelRatio, -frameState.pixelRatio, 0, 0, -frameState.size[1] ); const event = new Event_default( type, this.inversePixelTransform_, frameState, context ); layer.dispatchEvent(event); } } /** * @param {WebGLRenderingContext} context The rendering context. * @param {import("../../Map.js").FrameState} frameState Frame state. * @protected */ preRender(context, frameState) { this.dispatchRenderEvent_(EventType_default2.PRERENDER, context, frameState); } /** * @param {WebGLRenderingContext} context The rendering context. * @param {import("../../Map.js").FrameState} frameState Frame state. * @protected */ postRender(context, frameState) { this.dispatchRenderEvent_(EventType_default2.POSTRENDER, context, frameState); } }; var Layer_default2 = WebGLLayerRenderer; // node_modules/ol/renderer/webgl/TileLayerBase.js var Uniforms = { TILE_TRANSFORM: "u_tileTransform", TRANSITION_ALPHA: "u_transitionAlpha", DEPTH: "u_depth", RENDER_EXTENT: "u_renderExtent", // intersection of layer, source, and view extent PATTERN_ORIGIN: "u_patternOrigin", RESOLUTION: "u_resolution", ZOOM: "u_zoom", GLOBAL_ALPHA: "u_globalAlpha", PROJECTION_MATRIX: "u_projectionMatrix", SCREEN_TO_WORLD_MATRIX: "u_screenToWorldMatrix" }; function depthForZ(z) { return 1 / (z + 2); } function newTileRepresentationLookup() { return { tileIds: /* @__PURE__ */ new Set(), representationsByZ: {} }; } function lookupHasTile(tileRepresentationLookup, tile) { return tileRepresentationLookup.tileIds.has(getUid(tile)); } function addTileRepresentationToLookup(tileRepresentationLookup, tileRepresentation, z) { const representationsByZ = tileRepresentationLookup.representationsByZ; if (!(z in representationsByZ)) { representationsByZ[z] = /* @__PURE__ */ new Set(); } representationsByZ[z].add(tileRepresentation); tileRepresentationLookup.tileIds.add(getUid(tileRepresentation.tile)); } function getRenderExtent(frameState, extent) { const layerState = frameState.layerStatesArray[frameState.layerIndex]; if (layerState.extent) { extent = getIntersection( extent, fromUserExtent(layerState.extent, frameState.viewState.projection) ); } const source = ( /** @type {import("../../source/Tile.js").default} */ layerState.layer.getRenderSource() ); if (!source.getWrapX()) { const gridExtent = source.getTileGridForProjection(frameState.viewState.projection).getExtent(); if (gridExtent) { extent = getIntersection(extent, gridExtent); } } return extent; } function getCacheKey(source, tileCoord) { return `${getUid(source)},${source.getKey()},${source.getRevision()},${getKey(tileCoord)}`; } var WebGLBaseTileLayerRenderer = class extends Layer_default2 { /** * @param {LayerType} tileLayer Tile layer. * @param {Options} options Options. */ constructor(tileLayer, options) { super(tileLayer, { uniforms: options.uniforms, postProcesses: options.postProcesses }); this.renderComplete = false; this.tileTransform_ = create(); this.tempMat4 = create2(); this.tempTileRange_ = new TileRange_default(0, 0, 0, 0); this.tempTileCoord_ = createOrUpdate(0, 0, 0); this.tempSize_ = [0, 0]; const cacheSize = options.cacheSize !== void 0 ? options.cacheSize : 512; this.tileRepresentationCache = new LRUCache_default(cacheSize); this.frameState = null; this.renderedProjection_ = void 0; } /** * @param {Options} options Options. * @override */ reset(options) { super.reset({ uniforms: options.uniforms }); } /** * Determine whether renderFrame should be called. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {boolean} Layer is ready to be rendered. * @override */ prepareFrameInternal(frameState) { if (!this.renderedProjection_) { this.renderedProjection_ = frameState.viewState.projection; } else if (frameState.viewState.projection !== this.renderedProjection_) { this.clearCache(); this.renderedProjection_ = frameState.viewState.projection; } const layer = this.getLayer(); const source = layer.getRenderSource(); if (!source) { return false; } if (isEmpty(getRenderExtent(frameState, frameState.extent))) { return false; } return source.getState() === "ready"; } /** * @abstract * @param {import("../../webgl/BaseTileRepresentation.js").TileRepresentationOptions} options tile representation options * @return {TileRepresentation} A new tile representation * @protected */ createTileRepresentation(options) { return abstract(); } /** * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {import("../../extent.js").Extent} extent The extent to be rendered. * @param {number} initialZ The zoom level. * @param {TileRepresentationLookup} tileRepresentationLookup The zoom level. * @param {number} preload Number of additional levels to load. */ enqueueTiles(frameState, extent, initialZ, tileRepresentationLookup, preload) { const viewState = frameState.viewState; const tileLayer = this.getLayer(); const tileSource = tileLayer.getRenderSource(); const tileGrid = tileSource.getTileGridForProjection(viewState.projection); const gutter = tileSource.getGutterForProjection(viewState.projection); const tileSourceKey = getUid(tileSource); if (!(tileSourceKey in frameState.wantedTiles)) { frameState.wantedTiles[tileSourceKey] = {}; } const wantedTiles = frameState.wantedTiles[tileSourceKey]; const tileRepresentationCache = this.tileRepresentationCache; const map = tileLayer.getMapInternal(); const minZ = Math.max( initialZ - preload, tileGrid.getMinZoom(), tileGrid.getZForResolution( Math.min( tileLayer.getMaxResolution(), map ? map.getView().getResolutionForZoom(Math.max(tileLayer.getMinZoom(), 0)) : tileGrid.getResolution(0) ), tileSource.zDirection ) ); const rotation = viewState.rotation; const viewport = rotation ? getRotatedViewport( viewState.center, viewState.resolution, rotation, frameState.size ) : void 0; for (let z = initialZ; z >= minZ; --z) { const tileRange = tileGrid.getTileRangeForExtentAndZ( extent, z, this.tempTileRange_ ); const tileResolution = tileGrid.getResolution(z); for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { if (rotation && !tileGrid.tileCoordIntersectsViewport([z, x, y], viewport)) { continue; } const tileCoord = createOrUpdate(z, x, y, this.tempTileCoord_); const cacheKey = getCacheKey(tileSource, tileCoord); let tileRepresentation; let tile; if (tileRepresentationCache.containsKey(cacheKey)) { tileRepresentation = tileRepresentationCache.get(cacheKey); tile = tileRepresentation.tile; } if (!tileRepresentation || tileRepresentation.tile.key !== tileSource.getKey()) { tile = tileSource.getTile( z, x, y, frameState.pixelRatio, viewState.projection ); if (!tile) { continue; } } if (lookupHasTile(tileRepresentationLookup, tile)) { continue; } if (!tileRepresentation) { tileRepresentation = this.createTileRepresentation({ tile, grid: tileGrid, helper: this.helper, gutter }); tileRepresentationCache.set(cacheKey, tileRepresentation); } else { tileRepresentation.setTile(tile); } addTileRepresentationToLookup( tileRepresentationLookup, tileRepresentation, z ); const tileQueueKey = tile.getKey(); wantedTiles[tileQueueKey] = true; if (tile.getState() === TileState_default.IDLE) { if (!frameState.tileQueue.isKeyQueued(tileQueueKey)) { frameState.tileQueue.enqueue([ tile, tileSourceKey, tileGrid.getTileCoordCenter(tileCoord), tileResolution ]); } } } } } } /** * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {boolean} tilesWithAlpha True if at least one of the rendered tiles has alpha * @protected */ beforeTilesRender(frameState, tilesWithAlpha) { this.helper.prepareDraw(this.frameState, !tilesWithAlpha, true); } /** * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {boolean} If returns false, tile mask rendering will be skipped * @protected */ beforeTilesMaskRender(frameState) { return false; } /** * @param {TileRepresentation} tileRepresentation Tile representation * @param {import("../../transform.js").Transform} tileTransform Tile transform * @param {import("../../Map.js").FrameState} frameState Frame state * @param {import("../../extent.js").Extent} renderExtent Render extent * @param {number} tileResolution Tile resolution * @param {import("../../size.js").Size} tileSize Tile size * @param {import("../../coordinate.js").Coordinate} tileOrigin Tile origin * @param {import("../../extent.js").Extent} tileExtent tile Extent * @param {number} depth Depth * @param {number} gutter Gutter * @param {number} alpha Alpha * @protected */ renderTile(tileRepresentation, tileTransform, frameState, renderExtent, tileResolution, tileSize, tileOrigin, tileExtent, depth, gutter, alpha) { } /** * @param {TileRepresentation} tileRepresentation Tile representation * @param {number} tileZ Tile Z * @param {import("../../extent.js").Extent} extent Render extent * @param {number} depth Depth * @protected */ renderTileMask(tileRepresentation, tileZ, extent, depth) { } drawTile_(frameState, tileRepresentation, tileZ, gutter, extent, alphaLookup, tileGrid) { if (!tileRepresentation.ready) { return; } const tile = tileRepresentation.tile; const tileCoord = tile.tileCoord; const tileCoordKey = getKey(tileCoord); const alpha = tileCoordKey in alphaLookup ? alphaLookup[tileCoordKey] : 1; const tileResolution = tileGrid.getResolution(tileZ); const tileSize = toSize(tileGrid.getTileSize(tileZ), this.tempSize_); const tileOrigin = tileGrid.getOrigin(tileZ); const tileExtent = tileGrid.getTileCoordExtent(tileCoord); const depth = alpha < 1 ? -1 : depthForZ(tileZ); if (alpha < 1) { frameState.animate = true; } const viewState = frameState.viewState; const centerX = viewState.center[0]; const centerY = viewState.center[1]; const tileWidthWithGutter = tileSize[0] + 2 * gutter; const tileHeightWithGutter = tileSize[1] + 2 * gutter; const aspectRatio = tileWidthWithGutter / tileHeightWithGutter; const centerI = (centerX - tileOrigin[0]) / (tileSize[0] * tileResolution); const centerJ = (tileOrigin[1] - centerY) / (tileSize[1] * tileResolution); const tileScale = viewState.resolution / tileResolution; const tileCenterI = tileCoord[1]; const tileCenterJ = tileCoord[2]; reset(this.tileTransform_); scale( this.tileTransform_, 2 / (frameState.size[0] * tileScale / tileWidthWithGutter), -2 / (frameState.size[1] * tileScale / tileWidthWithGutter) ); rotate(this.tileTransform_, viewState.rotation); scale(this.tileTransform_, 1, 1 / aspectRatio); translate( this.tileTransform_, (tileSize[0] * (tileCenterI - centerI) - gutter) / tileWidthWithGutter, (tileSize[1] * (tileCenterJ - centerJ) - gutter) / tileHeightWithGutter ); this.renderTile( /** @type {TileRepresentation} */ tileRepresentation, this.tileTransform_, frameState, extent, tileResolution, tileSize, tileOrigin, tileExtent, depth, gutter, alpha ); } /** * Render the layer. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {HTMLElement} The rendered element. * @override */ renderFrame(frameState) { this.frameState = frameState; this.renderComplete = true; const gl = this.helper.getGL(); this.preRender(gl, frameState); const viewState = frameState.viewState; const tileLayer = this.getLayer(); const tileSource = tileLayer.getRenderSource(); const tileGrid = tileSource.getTileGridForProjection(viewState.projection); const gutter = tileSource.getGutterForProjection(viewState.projection); const extent = getRenderExtent(frameState, frameState.extent); const z = tileGrid.getZForResolution( viewState.resolution, tileSource.zDirection ); const tileRepresentationLookup = newTileRepresentationLookup(); const preload = tileLayer.getPreload(); if (frameState.nextExtent) { const targetZ = tileGrid.getZForResolution( viewState.nextResolution, tileSource.zDirection ); const nextExtent = getRenderExtent(frameState, frameState.nextExtent); this.enqueueTiles( frameState, nextExtent, targetZ, tileRepresentationLookup, preload ); } this.enqueueTiles(frameState, extent, z, tileRepresentationLookup, 0); if (preload > 0) { setTimeout(() => { this.enqueueTiles( frameState, extent, z - 1, tileRepresentationLookup, preload - 1 ); }, 0); } const alphaLookup = {}; let blend = false; const representationsByZ = tileRepresentationLookup.representationsByZ; if (z in representationsByZ) { const uid = getUid(this); const time = frameState.time; for (const tileRepresentation of representationsByZ[z]) { const tile = tileRepresentation.tile; if (tile.getState() === TileState_default.EMPTY) { continue; } const tileCoord = tile.tileCoord; if (tileRepresentation.ready) { const alpha = tile.getAlpha(uid, time); if (alpha === 1) { tile.endTransition(uid); continue; } blend = true; const tileCoordKey = getKey(tileCoord); alphaLookup[tileCoordKey] = alpha; } this.renderComplete = false; const coveredByChildren = this.findAltTiles_( tileGrid, tileCoord, z + 1, tileRepresentationLookup ); if (coveredByChildren) { continue; } const minZoom = tileGrid.getMinZoom(); for (let parentZ = z - 1; parentZ >= minZoom; --parentZ) { const coveredByParent = this.findAltTiles_( tileGrid, tileCoord, parentZ, tileRepresentationLookup ); if (coveredByParent) { break; } } } } const zs = Object.keys(representationsByZ).map(Number).sort(descending); const renderTileMask = this.beforeTilesMaskRender(frameState); if (renderTileMask) { for (let j = 0, jj = zs.length; j < jj; ++j) { const tileZ = zs[j]; for (const tileRepresentation of representationsByZ[tileZ]) { const tileCoord = tileRepresentation.tile.tileCoord; const tileCoordKey = getKey(tileCoord); if (tileCoordKey in alphaLookup) { continue; } const tileExtent = tileGrid.getTileCoordExtent(tileCoord); this.renderTileMask( /** @type {TileRepresentation} */ tileRepresentation, tileZ, tileExtent, depthForZ(tileZ) ); } } } this.beforeTilesRender(frameState, blend); for (let j = 0, jj = zs.length; j < jj; ++j) { const tileZ = zs[j]; for (const tileRepresentation of representationsByZ[tileZ]) { const tileCoord = tileRepresentation.tile.tileCoord; const tileCoordKey = getKey(tileCoord); if (tileCoordKey in alphaLookup) { continue; } this.drawTile_( frameState, tileRepresentation, tileZ, gutter, extent, alphaLookup, tileGrid ); } } if (z in representationsByZ) { for (const tileRepresentation of representationsByZ[z]) { const tileCoord = tileRepresentation.tile.tileCoord; const tileCoordKey = getKey(tileCoord); if (tileCoordKey in alphaLookup) { this.drawTile_( frameState, tileRepresentation, z, gutter, extent, alphaLookup, tileGrid ); } } } this.beforeFinalize(frameState); this.helper.finalizeDraw( frameState, this.dispatchPreComposeEvent, this.dispatchPostComposeEvent ); const canvas = this.helper.getCanvas(); const tileRepresentationCache = this.tileRepresentationCache; tileRepresentationCache.expireCache(); this.postRender(gl, frameState); return canvas; } /** * @param {import("../../Map.js").FrameState} frameState Frame state. * @protected */ beforeFinalize(frameState) { return; } /** * Look for tiles covering the provided tile coordinate at an alternate * zoom level. Loaded tiles will be added to the provided tile representation lookup. * @param {import("../../tilegrid/TileGrid.js").default} tileGrid The tile grid. * @param {import("../../tilecoord.js").TileCoord} tileCoord The target tile coordinate. * @param {number} altZ The alternate zoom level. * @param {TileRepresentationLookup} tileRepresentationLookup Lookup of * tile representations by zoom level. * @return {boolean} The tile coordinate is covered by loaded tiles at the alternate zoom level. * @private */ findAltTiles_(tileGrid, tileCoord, altZ, tileRepresentationLookup) { const tileRange = tileGrid.getTileRangeForTileCoordAndZ( tileCoord, altZ, this.tempTileRange_ ); if (!tileRange) { return false; } let covered = true; const tileRepresentationCache = this.tileRepresentationCache; const source = this.getLayer().getRenderSource(); for (let x = tileRange.minX; x <= tileRange.maxX; ++x) { for (let y = tileRange.minY; y <= tileRange.maxY; ++y) { const cacheKey = getCacheKey(source, [altZ, x, y]); let loaded = false; if (tileRepresentationCache.containsKey(cacheKey)) { const tileRepresentation = tileRepresentationCache.get(cacheKey); if (tileRepresentation.ready && !lookupHasTile(tileRepresentationLookup, tileRepresentation.tile)) { addTileRepresentationToLookup( tileRepresentationLookup, tileRepresentation, altZ ); loaded = true; } } if (!loaded) { covered = false; } } } return covered; } /** * @override */ clearCache() { super.clearCache(); const tileRepresentationCache = this.tileRepresentationCache; tileRepresentationCache.forEach( (tileRepresentation) => tileRepresentation.dispose() ); tileRepresentationCache.clear(); } /** * @override */ afterHelperCreated() { super.afterHelperCreated(); this.tileRepresentationCache.forEach( (tileRepresentation) => tileRepresentation.setHelper(this.helper) ); } /** * Clean up. * @override */ disposeInternal() { super.disposeInternal(); delete this.frameState; } }; var TileLayerBase_default = WebGLBaseTileLayerRenderer; // node_modules/ol/renderer/webgl/TileLayer.js var Uniforms2 = { ...Uniforms, TILE_TEXTURE_ARRAY: "u_tileTextures", TEXTURE_PIXEL_WIDTH: "u_texturePixelWidth", TEXTURE_PIXEL_HEIGHT: "u_texturePixelHeight", TEXTURE_RESOLUTION: "u_textureResolution", // map units per texture pixel TEXTURE_ORIGIN_X: "u_textureOriginX", // map x coordinate of left edge of texture TEXTURE_ORIGIN_Y: "u_textureOriginY" // map y coordinate of top edge of texture }; var Attributes = { TEXTURE_COORD: "a_textureCoord" }; var attributeDescriptions = [ { name: Attributes.TEXTURE_COORD, size: 2, type: AttributeType.FLOAT } ]; var WebGLTileLayerRenderer = class extends TileLayerBase_default { /** * @param {LayerType} tileLayer Tile layer. * @param {Options} options Options. */ constructor(tileLayer, options) { super(tileLayer, options); this.program_; this.vertexShader_ = options.vertexShader; this.fragmentShader_ = options.fragmentShader; this.indices_ = new Buffer_default(ELEMENT_ARRAY_BUFFER, STATIC_DRAW); this.indices_.fromArray([0, 1, 3, 1, 2, 3]); this.paletteTextures_ = options.paletteTextures || []; } /** * @param {Options} options Options. * @override */ reset(options) { super.reset(options); if (this.helper) { const gl = this.helper.getGL(); for (const paletteTexture of this.paletteTextures_) { paletteTexture.delete(gl); } } this.vertexShader_ = options.vertexShader; this.fragmentShader_ = options.fragmentShader; this.paletteTextures_ = options.paletteTextures || []; if (this.helper) { this.program_ = this.helper.getProgram( this.fragmentShader_, this.vertexShader_ ); const gl = this.helper.getGL(); for (const paletteTexture of this.paletteTextures_) { paletteTexture.getTexture(gl); } } } /** * @override */ afterHelperCreated() { super.afterHelperCreated(); const gl = this.helper.getGL(); for (const paletteTexture of this.paletteTextures_) { paletteTexture.getTexture(gl); } this.program_ = this.helper.getProgram( this.fragmentShader_, this.vertexShader_ ); this.helper.flushBufferData(this.indices_); } /** * @override */ removeHelper() { if (this.helper) { const gl = this.helper.getGL(); for (const paletteTexture of this.paletteTextures_) { paletteTexture.delete(gl); } } super.removeHelper(); } /** * @override */ createTileRepresentation(options) { return new TileTexture_default(options); } /** * @override */ beforeTilesRender(frameState, tilesWithAlpha) { super.beforeTilesRender(frameState, tilesWithAlpha); this.helper.useProgram(this.program_, frameState); } /** * @override */ renderTile(tileTexture, tileTransform, frameState, renderExtent, tileResolution, tileSize, tileOrigin, tileExtent, depth, gutter, alpha) { const gl = this.helper.getGL(); this.helper.bindBuffer(tileTexture.coords); this.helper.bindBuffer(this.indices_); this.helper.enableAttributes(attributeDescriptions); let textureSlot = 0; while (textureSlot < tileTexture.textures.length) { const uniformName = `${Uniforms2.TILE_TEXTURE_ARRAY}[${textureSlot}]`; this.helper.bindTexture( tileTexture.textures[textureSlot], textureSlot, uniformName ); ++textureSlot; } for (let paletteIndex = 0; paletteIndex < this.paletteTextures_.length; ++paletteIndex) { const paletteTexture = this.paletteTextures_[paletteIndex]; const texture = paletteTexture.getTexture(gl); this.helper.bindTexture(texture, textureSlot, paletteTexture.name); ++textureSlot; } const viewState = frameState.viewState; const tileWidthWithGutter = tileSize[0] + 2 * gutter; const tileHeightWithGutter = tileSize[1] + 2 * gutter; const tile = tileTexture.tile; const tileCoord = tile.tileCoord; const tileCenterI = tileCoord[1]; const tileCenterJ = tileCoord[2]; this.helper.setUniformMatrixValue( Uniforms2.TILE_TRANSFORM, fromTransform(this.tempMat4, tileTransform) ); this.helper.setUniformFloatValue(Uniforms2.TRANSITION_ALPHA, alpha); this.helper.setUniformFloatValue(Uniforms2.DEPTH, depth); let gutterExtent = renderExtent; if (gutter > 0) { gutterExtent = tileExtent; getIntersection(gutterExtent, renderExtent, gutterExtent); } this.helper.setUniformFloatVec4(Uniforms2.RENDER_EXTENT, gutterExtent); this.helper.setUniformFloatValue(Uniforms2.RESOLUTION, viewState.resolution); this.helper.setUniformFloatValue(Uniforms2.ZOOM, viewState.zoom); this.helper.setUniformFloatValue( Uniforms2.TEXTURE_PIXEL_WIDTH, tileWidthWithGutter ); this.helper.setUniformFloatValue( Uniforms2.TEXTURE_PIXEL_HEIGHT, tileHeightWithGutter ); this.helper.setUniformFloatValue( Uniforms2.TEXTURE_RESOLUTION, tileResolution ); this.helper.setUniformFloatValue( Uniforms2.TEXTURE_ORIGIN_X, tileOrigin[0] + tileCenterI * tileSize[0] * tileResolution - gutter * tileResolution ); this.helper.setUniformFloatValue( Uniforms2.TEXTURE_ORIGIN_Y, tileOrigin[1] - tileCenterJ * tileSize[1] * tileResolution + gutter * tileResolution ); this.helper.drawElements(0, this.indices_.getSize()); } /** * @param {import("../../pixel.js").Pixel} pixel Pixel. * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView} Data at the pixel location. * @override */ getData(pixel) { const gl = this.helper.getGL(); if (!gl) { return null; } const frameState = this.frameState; if (!frameState) { return null; } const layer = this.getLayer(); const coordinate = apply( frameState.pixelToCoordinateTransform, pixel.slice() ); const viewState = frameState.viewState; const layerExtent = layer.getExtent(); if (layerExtent) { if (!containsCoordinate( fromUserExtent(layerExtent, viewState.projection), coordinate )) { return null; } } const sources = layer.getSources( boundingExtent([coordinate]), viewState.resolution ); let i, source, tileGrid; for (i = sources.length - 1; i >= 0; --i) { source = sources[i]; if (source.getState() === "ready") { tileGrid = source.getTileGridForProjection(viewState.projection); if (source.getWrapX()) { break; } const gridExtent = tileGrid.getExtent(); if (!gridExtent || containsCoordinate(gridExtent, coordinate)) { break; } } } if (i < 0) { return null; } const tileTextureCache = this.tileRepresentationCache; for (let z = tileGrid.getZForResolution(viewState.resolution); z >= tileGrid.getMinZoom(); --z) { const tileCoord = tileGrid.getTileCoordForCoordAndZ(coordinate, z); const cacheKey = getCacheKey(source, tileCoord); if (!tileTextureCache.containsKey(cacheKey)) { continue; } const tileTexture = tileTextureCache.get(cacheKey); const tile = tileTexture.tile; if (tile.getState() === TileState_default.EMPTY) { return null; } if (!tileTexture.loaded) { continue; } const tileOrigin = tileGrid.getOrigin(z); const tileSize = toSize(tileGrid.getTileSize(z)); const tileResolution = tileGrid.getResolution(z); const col = (coordinate[0] - tileOrigin[0]) / tileResolution - tileCoord[1] * tileSize[0]; const row = (tileOrigin[1] - coordinate[1]) / tileResolution - tileCoord[2] * tileSize[1]; return tileTexture.getPixelData(col, row); } return null; } /** * Clean up. * @override */ disposeInternal() { const helper = this.helper; if (helper) { const gl = helper.getGL(); for (const paletteTexture of this.paletteTextures_) { paletteTexture.delete(gl); } this.paletteTextures_.length = 0; gl.deleteProgram(this.program_); delete this.program_; helper.deleteBuffer(this.indices_); } super.disposeInternal(); delete this.indices_; } }; var TileLayer_default2 = WebGLTileLayerRenderer; // node_modules/ol/webgl/PaletteTexture.js var PaletteTexture = class { /** * @param {string} name The name of the texture. * @param {Uint8Array} data The texture data. */ constructor(name, data) { this.name = name; this.data = data; this.texture_ = null; } /** * @param {WebGLRenderingContext} gl Rendering context. * @return {WebGLTexture} The texture. */ getTexture(gl) { if (!this.texture_) { const texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, this.data.length / 4, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.data ); this.texture_ = texture; } return this.texture_; } /** * @param {WebGLRenderingContext} gl Rendering context. */ delete(gl) { if (this.texture_) { gl.deleteTexture(this.texture_); } this.texture_ = null; } }; var PaletteTexture_default = PaletteTexture; // node_modules/ol/expr/gpu.js function computeOperatorFunctionName(operator, context) { return `operator_${operator}_${Object.keys(context.functions).length}`; } function numberToGlsl(v) { const s = v.toString(); return s.includes(".") ? s : s + ".0"; } function arrayToGlsl(array) { if (array.length < 2 || array.length > 4) { throw new Error( "`formatArray` can only output `vec2`, `vec3` or `vec4` arrays." ); } return `vec${array.length}(${array.map(numberToGlsl).join(", ")})`; } function colorToGlsl(color) { const array = asArray(color); const alpha = array.length > 3 ? array[3] : 1; return arrayToGlsl([array[0] / 255, array[1] / 255, array[2] / 255, alpha]); } function sizeToGlsl(size) { const array = toSize(size); return arrayToGlsl(array); } var stringToFloatMap = {}; var stringToFloatCounter = 0; function getStringNumberEquivalent(string) { if (!(string in stringToFloatMap)) { stringToFloatMap[string] = stringToFloatCounter++; } return stringToFloatMap[string]; } function stringToGlsl(string) { return numberToGlsl(getStringNumberEquivalent(string)); } function uniformNameForVariable(variableName) { return "u_var_" + variableName; } function newCompilationContext() { return { variables: {}, properties: {}, functions: {}, bandCount: 0, featureId: false, geometryType: false }; } var GET_BAND_VALUE_FUNC = "getBandValue"; var PALETTE_TEXTURE_ARRAY = "u_paletteTextures"; var FEATURE_ID_PROPERTY_NAME = "featureId"; var GEOMETRY_TYPE_PROPERTY_NAME = "geometryType"; var UNDEFINED_PROP_VALUE = -9999999; function buildExpression(encoded, type, parsingContext, compilationContext) { const expression = parse(encoded, type, parsingContext); return compile(expression, type, compilationContext); } function createCompiler(output) { return (context, expression, type) => { const length = expression.args.length; const args = new Array(length); for (let i = 0; i < length; ++i) { args[i] = compile(expression.args[i], type, context); } return output(args, context); }; } var compilers = { [Ops.Get]: (context, expression) => { const firstArg = ( /** @type {LiteralExpression} */ expression.args[0] ); const propName = ( /** @type {string} */ firstArg.value ); const isExisting = propName in context.properties; if (!isExisting) { context.properties[propName] = { name: propName, type: expression.type }; } let result = "a_prop_" + propName; if (isType(expression.type, BooleanType)) { result = `(${result} > 0.0)`; } return result; }, [Ops.Id]: (context) => { context.featureId = true; return "a_" + FEATURE_ID_PROPERTY_NAME; }, [Ops.GeometryType]: (context) => { context.geometryType = true; return "a_" + GEOMETRY_TYPE_PROPERTY_NAME; }, [Ops.LineMetric]: () => "currentLineMetric", // this variable is assumed to always be present in shaders, default is 0. [Ops.Var]: (context, expression) => { const firstArg = ( /** @type {LiteralExpression} */ expression.args[0] ); const varName = ( /** @type {string} */ firstArg.value ); const isExisting = varName in context.variables; if (!isExisting) { context.variables[varName] = { name: varName, type: expression.type }; } let result = uniformNameForVariable(varName); if (isType(expression.type, BooleanType)) { result = `(${result} > 0.0)`; } return result; }, [Ops.Has]: (context, expression) => { const firstArg = ( /** @type {LiteralExpression} */ expression.args[0] ); const propName = ( /** @type {string} */ firstArg.value ); const isExisting = propName in context.properties; if (!isExisting) { context.properties[propName] = { name: propName, type: expression.type }; } return `(a_prop_${propName} != ${numberToGlsl(UNDEFINED_PROP_VALUE)})`; }, [Ops.Resolution]: () => "u_resolution", [Ops.Zoom]: () => "u_zoom", [Ops.Time]: () => "u_time", [Ops.Any]: createCompiler((compiledArgs) => `(${compiledArgs.join(` || `)})`), [Ops.All]: createCompiler((compiledArgs) => `(${compiledArgs.join(` && `)})`), [Ops.Not]: createCompiler(([value]) => `(!${value})`), [Ops.Equal]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} == ${secondValue})` ), [Ops.NotEqual]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} != ${secondValue})` ), [Ops.GreaterThan]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} > ${secondValue})` ), [Ops.GreaterThanOrEqualTo]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} >= ${secondValue})` ), [Ops.LessThan]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} < ${secondValue})` ), [Ops.LessThanOrEqualTo]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} <= ${secondValue})` ), [Ops.Multiply]: createCompiler( (compiledArgs) => `(${compiledArgs.join(" * ")})` ), [Ops.Divide]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} / ${secondValue})` ), [Ops.Add]: createCompiler((compiledArgs) => `(${compiledArgs.join(" + ")})`), [Ops.Subtract]: createCompiler( ([firstValue, secondValue]) => `(${firstValue} - ${secondValue})` ), [Ops.Clamp]: createCompiler( ([value, min, max]) => `clamp(${value}, ${min}, ${max})` ), [Ops.Mod]: createCompiler(([value, modulo]) => `mod(${value}, ${modulo})`), [Ops.Pow]: createCompiler(([value, power]) => `pow(${value}, ${power})`), [Ops.Abs]: createCompiler(([value]) => `abs(${value})`), [Ops.Floor]: createCompiler(([value]) => `floor(${value})`), [Ops.Ceil]: createCompiler(([value]) => `ceil(${value})`), [Ops.Round]: createCompiler(([value]) => `floor(${value} + 0.5)`), [Ops.Sin]: createCompiler(([value]) => `sin(${value})`), [Ops.Cos]: createCompiler(([value]) => `cos(${value})`), [Ops.Atan]: createCompiler(([firstValue, secondValue]) => { return secondValue !== void 0 ? `atan(${firstValue}, ${secondValue})` : `atan(${firstValue})`; }), [Ops.Sqrt]: createCompiler(([value]) => `sqrt(${value})`), [Ops.Match]: createCompiler((compiledArgs) => { const input = compiledArgs[0]; const fallback = compiledArgs[compiledArgs.length - 1]; let result = null; for (let i = compiledArgs.length - 3; i >= 1; i -= 2) { const match = compiledArgs[i]; const output = compiledArgs[i + 1]; result = `(${input} == ${match} ? ${output} : ${result || fallback})`; } return result; }), [Ops.Between]: createCompiler( ([value, min, max]) => `(${value} >= ${min} && ${value} <= ${max})` ), [Ops.Interpolate]: createCompiler(([exponent, input, ...compiledArgs]) => { let result = ""; for (let i = 0; i < compiledArgs.length - 2; i += 2) { const stop1 = compiledArgs[i]; const output1 = result || compiledArgs[i + 1]; const stop2 = compiledArgs[i + 2]; const output2 = compiledArgs[i + 3]; let ratio; if (exponent === numberToGlsl(1)) { ratio = `(${input} - ${stop1}) / (${stop2} - ${stop1})`; } else { ratio = `(pow(${exponent}, (${input} - ${stop1})) - 1.0) / (pow(${exponent}, (${stop2} - ${stop1})) - 1.0)`; } result = `mix(${output1}, ${output2}, clamp(${ratio}, 0.0, 1.0))`; } return result; }), [Ops.Case]: createCompiler((compiledArgs) => { const fallback = compiledArgs[compiledArgs.length - 1]; let result = null; for (let i = compiledArgs.length - 3; i >= 0; i -= 2) { const condition = compiledArgs[i]; const output = compiledArgs[i + 1]; result = `(${condition} ? ${output} : ${result || fallback})`; } return result; }), [Ops.In]: createCompiler(([needle, ...haystack], context) => { const funcName = computeOperatorFunctionName("in", context); const tests = []; for (let i = 0; i < haystack.length; i += 1) { tests.push(` if (inputValue == ${haystack[i]}) { return true; }`); } context.functions[funcName] = `bool ${funcName}(float inputValue) { ${tests.join("\n")} return false; }`; return `${funcName}(${needle})`; }), [Ops.Array]: createCompiler( (args) => `vec${args.length}(${args.join(", ")})` ), [Ops.Color]: createCompiler((compiledArgs) => { if (compiledArgs.length === 1) { return `vec4(vec3(${compiledArgs[0]} / 255.0), 1.0)`; } if (compiledArgs.length === 2) { return `vec4(vec3(${compiledArgs[0]} / 255.0), ${compiledArgs[1]})`; } const rgb = compiledArgs.slice(0, 3).map((color) => `${color} / 255.0`); if (compiledArgs.length === 3) { return `vec4(${rgb.join(", ")}, 1.0)`; } const alpha = compiledArgs[3]; return `vec4(${rgb.join(", ")}, ${alpha})`; }), [Ops.Band]: createCompiler(([band, xOffset, yOffset], context) => { if (!(GET_BAND_VALUE_FUNC in context.functions)) { let ifBlocks = ""; const bandCount = context.bandCount || 1; for (let i = 0; i < bandCount; i++) { const colorIndex = Math.floor(i / 4); let bandIndex = i % 4; if (i === bandCount - 1 && bandIndex === 1) { bandIndex = 3; } const textureName = `${Uniforms2.TILE_TEXTURE_ARRAY}[${colorIndex}]`; ifBlocks += ` if (band == ${i + 1}.0) { return texture2D(${textureName}, v_textureCoord + vec2(dx, dy))[${bandIndex}]; } `; } context.functions[GET_BAND_VALUE_FUNC] = `float getBandValue(float band, float xOffset, float yOffset) { float dx = xOffset / ${Uniforms2.TEXTURE_PIXEL_WIDTH}; float dy = yOffset / ${Uniforms2.TEXTURE_PIXEL_HEIGHT}; ${ifBlocks} }`; } return `${GET_BAND_VALUE_FUNC}(${band}, ${xOffset ?? "0.0"}, ${yOffset ?? "0.0"})`; }), [Ops.Palette]: (context, expression) => { const [index, ...colors] = expression.args; const numColors = colors.length; const palette = new Uint8Array(numColors * 4); for (let i = 0; i < colors.length; i++) { const parsedValue = ( /** @type {string | Array} */ /** @type {LiteralExpression} */ colors[i].value ); const color = asArray(parsedValue); const offset = i * 4; palette[offset] = color[0]; palette[offset + 1] = color[1]; palette[offset + 2] = color[2]; palette[offset + 3] = color[3] * 255; } if (!context.paletteTextures) { context.paletteTextures = []; } const paletteName = `${PALETTE_TEXTURE_ARRAY}[${context.paletteTextures.length}]`; const paletteTexture = new PaletteTexture_default(paletteName, palette); context.paletteTextures.push(paletteTexture); const compiledIndex = compile(index, NumberType, context); return `texture2D(${paletteName}, vec2((${compiledIndex} + 0.5) / ${numColors}.0, 0.5))`; } // TODO: unimplemented // Ops.Number // Ops.String // Ops.Coalesce // Ops.Concat // Ops.ToString }; function compile(expression, returnType, context) { if (expression instanceof CallExpression) { const compiler = compilers[expression.operator]; if (compiler === void 0) { throw new Error( `No compiler defined for this operator: ${JSON.stringify( expression.operator )}` ); } return compiler(context, expression, returnType); } if ((expression.type & NumberType) > 0) { return numberToGlsl( /** @type {number} */ expression.value ); } if ((expression.type & BooleanType) > 0) { return expression.value.toString(); } if ((expression.type & StringType) > 0) { return stringToGlsl(expression.value.toString()); } if ((expression.type & ColorType) > 0) { return colorToGlsl( /** @type {Array | string} */ expression.value ); } if ((expression.type & NumberArrayType) > 0) { return arrayToGlsl( /** @type {Array} */ expression.value ); } if ((expression.type & SizeType) > 0) { return sizeToGlsl( /** @type {number|import('../size.js').Size} */ expression.value ); } throw new Error( `Unexpected expression ${expression.value} (expected type ${typeName( returnType )})` ); } // node_modules/ol/style/flat.js function createDefaultStyle() { return { "fill-color": "rgba(255,255,255,0.4)", "stroke-color": "#3399CC", "stroke-width": 1.25, "circle-radius": 5, "circle-fill-color": "rgba(255,255,255,0.4)", "circle-stroke-width": 1.25, "circle-stroke-color": "#3399CC" }; } // node_modules/ol/render/webgl/bufferUtil.js var LINESTRING_ANGLE_COSINE_CUTOFF = 0.985; // node_modules/ol/render/webgl/compileUtil.js function expressionToGlsl(compilationContext, value, expectedType) { const parsingContext = newParsingContext(); return buildExpression( value, expectedType, parsingContext, compilationContext ); } function packColor(color) { const array = asArray(color); const r = array[0] * 256; const g = array[1]; const b = array[2] * 256; const a = Math.round(array[3] * 255); return [r + g, b + a]; } var UNPACK_COLOR_FN = `vec4 unpackColor(vec2 packedColor) { return vec4( min(floor(packedColor[0] / 256.0) / 255.0, 1.0), min(mod(packedColor[0], 256.0) / 255.0, 1.0), min(floor(packedColor[1] / 256.0) / 255.0, 1.0), min(mod(packedColor[1], 256.0) / 255.0, 1.0) ); }`; function getGlslSizeFromType(type) { if (type === ColorType || type === SizeType) { return 2; } if (type === NumberArrayType) { return 4; } return 1; } function getGlslTypeFromType(type) { const size = getGlslSizeFromType(type); if (size > 1) { return ( /** @type {'vec2'|'vec3'|'vec4'} */ `vec${size}` ); } return "float"; } function applyContextToBuilder(builder, context) { for (const varName in context.variables) { const variable = context.variables[varName]; const uniformName = uniformNameForVariable(variable.name); let glslType = getGlslTypeFromType(variable.type); if (variable.type === ColorType) { glslType = "vec4"; } builder.addUniform(uniformName, glslType); } for (const propName in context.properties) { const property = context.properties[propName]; const glslType = getGlslTypeFromType(property.type); const attributeName = `a_prop_${property.name}`; if (property.type === ColorType) { builder.addAttribute( attributeName, glslType, `unpackColor(${attributeName})`, "vec4" ); } else { builder.addAttribute(attributeName, glslType); } } for (const functionName in context.functions) { builder.addVertexShaderFunction(context.functions[functionName]); builder.addFragmentShaderFunction(context.functions[functionName]); } } function generateUniformsFromContext(context, variables) { const uniforms = {}; for (const varName in context.variables) { const variable = context.variables[varName]; const uniformName = uniformNameForVariable(variable.name); uniforms[uniformName] = () => { const value = variables[variable.name]; if (typeof value === "number") { return value; } if (typeof value === "boolean") { return value ? 1 : 0; } if (variable.type === ColorType) { const color = [...asArray(value || "#eee")]; color[0] /= 255; color[1] /= 255; color[2] /= 255; color[3] ?? (color[3] = 1); return color; } if (typeof value === "string") { return getStringNumberEquivalent(value); } return value; }; } return uniforms; } function generateAttributesFromContext(context) { const attributes = {}; for (const propName in context.properties) { const property = context.properties[propName]; const callback = (feature) => { const value = feature.get(property.name); if (property.type === ColorType) { return packColor([...asArray(value || "#eee")]); } if (typeof value === "string") { return getStringNumberEquivalent(value); } if (typeof value === "boolean") { return value ? 1 : 0; } return value; }; attributes[`prop_${property.name}`] = { size: getGlslSizeFromType(property.type), callback }; } return attributes; } // node_modules/ol/render/webgl/ShaderBuilder.js var COMMON_HEADER = `#ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif uniform mat4 u_projectionMatrix; uniform mat4 u_screenToWorldMatrix; uniform vec2 u_viewportSizePx; uniform float u_pixelRatio; uniform float u_globalAlpha; uniform float u_time; uniform float u_zoom; uniform float u_resolution; uniform float u_rotation; uniform vec4 u_renderExtent; uniform vec2 u_patternOrigin; uniform float u_depth; uniform mediump int u_hitDetection; const float PI = 3.141592653589793238; const float TWO_PI = 2.0 * PI; float currentLineMetric = 0.; // an actual value will be used in the stroke shaders ${UNPACK_COLOR_FN} `; var DEFAULT_STYLE = createDefaultStyle(); var ShaderBuilder = class { constructor() { this.uniforms_ = []; this.attributes_ = []; this.hasSymbol_ = false; this.symbolSizeExpression_ = `vec2(${numberToGlsl( DEFAULT_STYLE["circle-radius"] )} + ${numberToGlsl(DEFAULT_STYLE["circle-stroke-width"] * 0.5)})`; this.symbolRotationExpression_ = "0.0"; this.symbolOffsetExpression_ = "vec2(0.0)"; this.symbolColorExpression_ = colorToGlsl( /** @type {string} */ DEFAULT_STYLE["circle-fill-color"] ); this.texCoordExpression_ = "vec4(0.0, 0.0, 1.0, 1.0)"; this.discardExpression_ = "false"; this.symbolRotateWithView_ = false; this.hasStroke_ = false; this.strokeWidthExpression_ = numberToGlsl(DEFAULT_STYLE["stroke-width"]); this.strokeColorExpression_ = colorToGlsl( /** @type {string} */ DEFAULT_STYLE["stroke-color"] ); this.strokeOffsetExpression_ = "0."; this.strokeCapExpression_ = stringToGlsl("round"); this.strokeJoinExpression_ = stringToGlsl("round"); this.strokeMiterLimitExpression_ = "10."; this.strokeDistanceFieldExpression_ = "-1000."; this.strokePatternLengthExpression_ = null; this.hasFill_ = false; this.fillColorExpression_ = colorToGlsl( /** @type {string} */ DEFAULT_STYLE["fill-color"] ); this.vertexShaderFunctions_ = []; this.fragmentShaderFunctions_ = []; } /** * Adds a uniform accessible in both fragment and vertex shaders. * The given name should include a type, such as `sampler2D u_texture`. * @param {string} name Uniform name, including the `u_` prefix * @param {'float'|'vec2'|'vec3'|'vec4'|'sampler2D'} type GLSL type * @return {ShaderBuilder} the builder object */ addUniform(name, type) { this.uniforms_.push({ name, type }); return this; } /** * Adds an attribute accessible in the vertex shader, read from the geometry buffer. * The given name should include a type, such as `vec2 a_position`. * Attributes will also be made available under the same name in fragment shaders. * @param {string} name Attribute name, including the `a_` prefix * @param {'float'|'vec2'|'vec3'|'vec4'} type GLSL type * @param {string} [varyingExpression] Expression which will be assigned to the varying in the vertex shader, and * passed on to the fragment shader. * @param {'float'|'vec2'|'vec3'|'vec4'} [varyingType] Type of the attribute after transformation; * e.g. `vec4` after unpacking color components * @return {ShaderBuilder} the builder object */ addAttribute(name, type, varyingExpression, varyingType) { this.attributes_.push({ name, type, varyingName: name.replace(/^a_/, "v_"), varyingType: varyingType ?? type, varyingExpression: varyingExpression ?? name }); return this; } /** * Sets an expression to compute the size of the shape. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `vec2` value. * @param {string} expression Size expression * @return {ShaderBuilder} the builder object */ setSymbolSizeExpression(expression) { this.hasSymbol_ = true; this.symbolSizeExpression_ = expression; return this; } /** * @return {string} The current symbol size expression */ getSymbolSizeExpression() { return this.symbolSizeExpression_; } /** * Sets an expression to compute the rotation of the shape. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `float` value in radians. * @param {string} expression Size expression * @return {ShaderBuilder} the builder object */ setSymbolRotationExpression(expression) { this.symbolRotationExpression_ = expression; return this; } /** * Sets an expression to compute the offset of the symbol from the point center. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `vec2` value. * @param {string} expression Offset expression * @return {ShaderBuilder} the builder object */ setSymbolOffsetExpression(expression) { this.symbolOffsetExpression_ = expression; return this; } /** * @return {string} The current symbol offset expression */ getSymbolOffsetExpression() { return this.symbolOffsetExpression_; } /** * Sets an expression to compute the color of the shape. * This expression can use all the uniforms, varyings and attributes available * in the fragment shader, and should evaluate to a `vec4` value. * @param {string} expression Color expression * @return {ShaderBuilder} the builder object */ setSymbolColorExpression(expression) { this.hasSymbol_ = true; this.symbolColorExpression_ = expression; return this; } /** * @return {string} The current symbol color expression */ getSymbolColorExpression() { return this.symbolColorExpression_; } /** * Sets an expression to compute the texture coordinates of the vertices. * This expression can use all the uniforms and attributes available * in the vertex shader, and should evaluate to a `vec4` value. * @param {string} expression Texture coordinate expression * @return {ShaderBuilder} the builder object */ setTextureCoordinateExpression(expression) { this.texCoordExpression_ = expression; return this; } /** * Sets an expression to determine whether a fragment (pixel) should be discarded, * i.e. not drawn at all. * This expression can use all the uniforms, varyings and attributes available * in the fragment shader, and should evaluate to a `bool` value (it will be * used in an `if` statement) * @param {string} expression Fragment discard expression * @return {ShaderBuilder} the builder object */ setFragmentDiscardExpression(expression) { this.discardExpression_ = expression; return this; } /** * @return {string} The current fragment discard expression */ getFragmentDiscardExpression() { return this.discardExpression_; } /** * Sets whether the symbols should rotate with the view or stay aligned with the map. * Note: will only be used for point geometry shaders. * @param {boolean} rotateWithView Rotate with view * @return {ShaderBuilder} the builder object */ setSymbolRotateWithView(rotateWithView) { this.symbolRotateWithView_ = rotateWithView; return this; } /** * @param {string} expression Stroke width expression, returning value in pixels * @return {ShaderBuilder} the builder object */ setStrokeWidthExpression(expression) { this.hasStroke_ = true; this.strokeWidthExpression_ = expression; return this; } /** * @param {string} expression Stroke color expression, evaluate to `vec4`: can rely on currentLengthPx and currentRadiusPx * @return {ShaderBuilder} the builder object */ setStrokeColorExpression(expression) { this.hasStroke_ = true; this.strokeColorExpression_ = expression; return this; } /** * @return {string} The current stroke color expression */ getStrokeColorExpression() { return this.strokeColorExpression_; } /** * @param {string} expression Stroke color expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeOffsetExpression(expression) { this.strokeOffsetExpression_ = expression; return this; } /** * @param {string} expression Stroke line cap expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeCapExpression(expression) { this.strokeCapExpression_ = expression; return this; } /** * @param {string} expression Stroke line join expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeJoinExpression(expression) { this.strokeJoinExpression_ = expression; return this; } /** * @param {string} expression Stroke miter limit expression, evaluate to `float` * @return {ShaderBuilder} the builder object */ setStrokeMiterLimitExpression(expression) { this.strokeMiterLimitExpression_ = expression; return this; } /** * @param {string} expression Stroke distance field expression, evaluate to `float` * This can override the default distance field; can rely on currentLengthPx and currentRadiusPx * @return {ShaderBuilder} the builder object */ setStrokeDistanceFieldExpression(expression) { this.strokeDistanceFieldExpression_ = expression; return this; } /** * Defining a pattern length for a stroke lets us avoid having visual artifacts when * a linestring is very long and thus has very high "distance" attributes on its vertices. * If we apply a pattern or dash array to a stroke we know for certain that the full distance value * is not necessary and can be trimmed down using `mod(currentDistance, patternLength)`. * @param {string} expression Stroke expression that evaluates to a`float; value is expected to be * in pixels. * @return {ShaderBuilder} the builder object */ setStrokePatternLengthExpression(expression) { this.strokePatternLengthExpression_ = expression; return this; } /** * @return {string} The current stroke pattern length expression. */ getStrokePatternLengthExpression() { return this.strokePatternLengthExpression_; } /** * @param {string} expression Fill color expression, evaluate to `vec4` * @return {ShaderBuilder} the builder object */ setFillColorExpression(expression) { this.hasFill_ = true; this.fillColorExpression_ = expression; return this; } /** * @return {string} The current fill color expression */ getFillColorExpression() { return this.fillColorExpression_; } addVertexShaderFunction(code) { if (this.vertexShaderFunctions_.includes(code)) { return this; } this.vertexShaderFunctions_.push(code); return this; } addFragmentShaderFunction(code) { if (this.fragmentShaderFunctions_.includes(code)) { return this; } this.fragmentShaderFunctions_.push(code); return this; } /** * Generates a symbol vertex shader from the builder parameters * @return {string|null} The full shader as a string; null if no size or color specified */ getSymbolVertexShader() { if (!this.hasSymbol_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} attribute vec2 a_position; attribute vec2 a_localPosition; attribute vec2 a_hitColor; varying vec2 v_texCoord; varying vec2 v_quadCoord; varying vec4 v_hitColor; varying vec2 v_centerPx; varying float v_angle; varying vec2 v_quadSizePx; ${this.attributes_.map( (attribute) => `attribute ${attribute.type} ${attribute.name}; varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.vertexShaderFunctions_.join("\n")} vec2 pxToScreen(vec2 coordPx) { vec2 scaled = coordPx / u_viewportSizePx / 0.5; return scaled; } vec2 screenToPx(vec2 coordScreen) { return (coordScreen * 0.5 + 0.5) * u_viewportSizePx; } void main(void) { v_quadSizePx = ${this.symbolSizeExpression_}; vec2 halfSizePx = v_quadSizePx * 0.5; vec2 centerOffsetPx = ${this.symbolOffsetExpression_}; vec2 offsetPx = centerOffsetPx + a_localPosition * halfSizePx * vec2(1., -1.); float angle = ${this.symbolRotationExpression_}${this.symbolRotateWithView_ ? " + u_rotation" : ""}; float c = cos(-angle); float s = sin(-angle); offsetPx = vec2(c * offsetPx.x - s * offsetPx.y, s * offsetPx.x + c * offsetPx.y); vec4 center = u_projectionMatrix * vec4(a_position, 0.0, 1.0); gl_Position = center + vec4(pxToScreen(offsetPx), u_depth, 0.); vec4 texCoord = ${this.texCoordExpression_}; float u = mix(texCoord.s, texCoord.p, a_localPosition.x * 0.5 + 0.5); float v = mix(texCoord.t, texCoord.q, a_localPosition.y * 0.5 + 0.5); v_texCoord = vec2(u, v); v_hitColor = unpackColor(a_hitColor); v_angle = angle; c = cos(-v_angle); s = sin(-v_angle); centerOffsetPx = vec2(c * centerOffsetPx.x - s * centerOffsetPx.y, s * centerOffsetPx.x + c * centerOffsetPx.y); v_centerPx = screenToPx(center.xy) + centerOffsetPx; ${this.attributes_.map( (attribute) => ` ${attribute.varyingName} = ${attribute.varyingExpression};` ).join("\n")} }`; } /** * Generates a symbol fragment shader from the builder parameters * @return {string|null} The full shader as a string; null if no size or color specified */ getSymbolFragmentShader() { if (!this.hasSymbol_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} varying vec2 v_texCoord; varying vec4 v_hitColor; varying vec2 v_centerPx; varying float v_angle; varying vec2 v_quadSizePx; ${this.attributes_.map( (attribute) => `varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.fragmentShaderFunctions_.join("\n")} void main(void) { ${this.attributes_.map( (attribute) => ` ${attribute.varyingType} ${attribute.name} = ${attribute.varyingName}; // assign to original attribute name` ).join("\n")} if (${this.discardExpression_}) { discard; } vec2 coordsPx = gl_FragCoord.xy / u_pixelRatio - v_centerPx; // relative to center float c = cos(v_angle); float s = sin(v_angle); coordsPx = vec2(c * coordsPx.x - s * coordsPx.y, s * coordsPx.x + c * coordsPx.y); gl_FragColor = ${this.symbolColorExpression_}; gl_FragColor.rgb *= gl_FragColor.a; if (u_hitDetection > 0) { if (gl_FragColor.a < 0.05) { discard; }; gl_FragColor = v_hitColor; } }`; } /** * Generates a stroke vertex shader from the builder parameters * @return {string|null} The full shader as a string; null if no size or color specified */ getStrokeVertexShader() { if (!this.hasStroke_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} attribute vec2 a_segmentStart; attribute vec2 a_segmentEnd; attribute vec2 a_localPosition; attribute float a_measureStart; attribute float a_measureEnd; attribute float a_angleTangentSum; attribute float a_distanceLow; attribute float a_distanceHigh; attribute vec2 a_joinAngles; attribute vec2 a_hitColor; varying vec2 v_segmentStartPx; varying vec2 v_segmentEndPx; varying float v_angleStart; varying float v_angleEnd; varying float v_width; varying vec4 v_hitColor; varying float v_distancePx; varying float v_measureStart; varying float v_measureEnd; ${this.attributes_.map( (attribute) => `attribute ${attribute.type} ${attribute.name}; varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.vertexShaderFunctions_.join("\n")} vec2 worldToPx(vec2 worldPos) { vec4 screenPos = u_projectionMatrix * vec4(worldPos, 0.0, 1.0); return (0.5 * screenPos.xy + 0.5) * u_viewportSizePx; } vec4 pxToScreen(vec2 pxPos) { vec2 screenPos = 2.0 * pxPos / u_viewportSizePx - 1.0; return vec4(screenPos, u_depth, 1.0); } bool isCap(float joinAngle) { return joinAngle < -0.1; } vec2 getJoinOffsetDirection(vec2 normalPx, float joinAngle) { float halfAngle = joinAngle / 2.0; float c = cos(halfAngle); float s = sin(halfAngle); vec2 angleBisectorNormal = vec2(s * normalPx.x + c * normalPx.y, -c * normalPx.x + s * normalPx.y); float length = 1.0 / s; return angleBisectorNormal * length; } vec2 getOffsetPoint(vec2 point, vec2 normal, float joinAngle, float offsetPx) { // if on a cap or the join angle is too high, offset the line along the segment normal if (cos(joinAngle) > 0.998 || isCap(joinAngle)) { return point - normal * offsetPx; } // offset is applied along the inverted normal (positive offset goes "right" relative to line direction) return point - getJoinOffsetDirection(normal, joinAngle) * offsetPx; } void main(void) { v_angleStart = a_joinAngles.x; v_angleEnd = a_joinAngles.y; float startEndRatio = a_localPosition.x * 0.5 + 0.5; currentLineMetric = mix(a_measureStart, a_measureEnd, startEndRatio); // we're reading the fractional part while keeping the sign (so -4.12 gives -0.12, 3.45 gives 0.45) float lineWidth = ${this.strokeWidthExpression_}; float lineOffsetPx = ${this.strokeOffsetExpression_}; // compute segment start/end in px with offset vec2 segmentStartPx = worldToPx(a_segmentStart); vec2 segmentEndPx = worldToPx(a_segmentEnd); vec2 tangentPx = normalize(segmentEndPx - segmentStartPx); vec2 normalPx = vec2(-tangentPx.y, tangentPx.x); segmentStartPx = getOffsetPoint(segmentStartPx, normalPx, v_angleStart, lineOffsetPx), segmentEndPx = getOffsetPoint(segmentEndPx, normalPx, v_angleEnd, lineOffsetPx); // compute current vertex position float normalDir = -1. * a_localPosition.y; float tangentDir = -1. * a_localPosition.x; float angle = mix(v_angleStart, v_angleEnd, startEndRatio); vec2 joinDirection; vec2 positionPx = mix(segmentStartPx, segmentEndPx, startEndRatio); // if angle is too high, do not make a proper join if (cos(angle) > ${LINESTRING_ANGLE_COSINE_CUTOFF} || isCap(angle)) { joinDirection = normalPx * normalDir - tangentPx * tangentDir; } else { joinDirection = getJoinOffsetDirection(normalPx * normalDir, angle); } positionPx = positionPx + joinDirection * (lineWidth * 0.5 + 1.); // adding 1 pixel for antialiasing gl_Position = pxToScreen(positionPx); v_segmentStartPx = segmentStartPx; v_segmentEndPx = segmentEndPx; v_width = lineWidth; v_hitColor = unpackColor(a_hitColor); v_distancePx = a_distanceLow / u_resolution - (lineOffsetPx * a_angleTangentSum); float distanceHighPx = a_distanceHigh / u_resolution; ${this.strokePatternLengthExpression_ !== null ? `v_distancePx = mod(v_distancePx, ${this.strokePatternLengthExpression_}); distanceHighPx = mod(distanceHighPx, ${this.strokePatternLengthExpression_}); ` : ""}v_distancePx += distanceHighPx; v_measureStart = a_measureStart; v_measureEnd = a_measureEnd; ${this.attributes_.map( (attribute) => ` ${attribute.varyingName} = ${attribute.varyingExpression};` ).join("\n")} }`; } /** * Generates a stroke fragment shader from the builder parameters * * @return {string|null} The full shader as a string; null if no size or color specified */ getStrokeFragmentShader() { if (!this.hasStroke_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} varying vec2 v_segmentStartPx; varying vec2 v_segmentEndPx; varying float v_angleStart; varying float v_angleEnd; varying float v_width; varying vec4 v_hitColor; varying float v_distancePx; varying float v_measureStart; varying float v_measureEnd; ${this.attributes_.map( (attribute) => `varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.fragmentShaderFunctions_.join("\n")} vec2 pxToWorld(vec2 pxPos) { vec2 screenPos = 2.0 * pxPos / u_viewportSizePx - 1.0; return (u_screenToWorldMatrix * vec4(screenPos, 0.0, 1.0)).xy; } bool isCap(float joinAngle) { return joinAngle < -0.1; } float segmentDistanceField(vec2 point, vec2 start, vec2 end, float width) { vec2 tangent = normalize(end - start); vec2 normal = vec2(-tangent.y, tangent.x); vec2 startToPoint = point - start; return abs(dot(startToPoint, normal)) - width * 0.5; } float buttCapDistanceField(vec2 point, vec2 start, vec2 end) { vec2 startToPoint = point - start; vec2 tangent = normalize(end - start); return dot(startToPoint, -tangent); } float squareCapDistanceField(vec2 point, vec2 start, vec2 end, float width) { return buttCapDistanceField(point, start, end) - width * 0.5; } float roundCapDistanceField(vec2 point, vec2 start, vec2 end, float width) { float onSegment = max(0., 1000. * dot(point - start, end - start)); // this is very high when inside the segment return length(point - start) - width * 0.5 - onSegment; } float roundJoinDistanceField(vec2 point, vec2 start, vec2 end, float width) { return roundCapDistanceField(point, start, end, width); } float bevelJoinField(vec2 point, vec2 start, vec2 end, float width, float joinAngle) { vec2 startToPoint = point - start; vec2 tangent = normalize(end - start); float c = cos(joinAngle * 0.5); float s = sin(joinAngle * 0.5); float direction = -sign(sin(joinAngle)); vec2 bisector = vec2(c * tangent.x - s * tangent.y, s * tangent.x + c * tangent.y); float radius = width * 0.5 * s; return dot(startToPoint, bisector * direction) - radius; } float miterJoinDistanceField(vec2 point, vec2 start, vec2 end, float width, float joinAngle) { if (cos(joinAngle) > ${LINESTRING_ANGLE_COSINE_CUTOFF}) { // avoid risking a division by zero return bevelJoinField(point, start, end, width, joinAngle); } float miterLength = 1. / sin(joinAngle * 0.5); float miterLimit = ${this.strokeMiterLimitExpression_}; if (miterLength > miterLimit) { return bevelJoinField(point, start, end, width, joinAngle); } return -1000.; } float capDistanceField(vec2 point, vec2 start, vec2 end, float width, float capType) { if (capType == ${stringToGlsl("butt")}) { return buttCapDistanceField(point, start, end); } else if (capType == ${stringToGlsl("square")}) { return squareCapDistanceField(point, start, end, width); } return roundCapDistanceField(point, start, end, width); } float joinDistanceField(vec2 point, vec2 start, vec2 end, float width, float joinAngle, float joinType) { if (joinType == ${stringToGlsl("bevel")}) { return bevelJoinField(point, start, end, width, joinAngle); } else if (joinType == ${stringToGlsl("miter")}) { return miterJoinDistanceField(point, start, end, width, joinAngle); } return roundJoinDistanceField(point, start, end, width); } float computeSegmentPointDistance(vec2 point, vec2 start, vec2 end, float width, float joinAngle, float capType, float joinType) { if (isCap(joinAngle)) { return capDistanceField(point, start, end, width, capType); } return joinDistanceField(point, start, end, width, joinAngle, joinType); } float distanceFromSegment(vec2 point, vec2 start, vec2 end) { vec2 tangent = end - start; vec2 startToPoint = point - start; // inspire by capsule fn in https://iquilezles.org/articles/distfunctions/ float h = clamp(dot(startToPoint, tangent) / dot(tangent, tangent), 0.0, 1.0); return length(startToPoint - tangent * h); } void main(void) { ${this.attributes_.map( (attribute) => ` ${attribute.varyingType} ${attribute.name} = ${attribute.varyingName}; // assign to original attribute name` ).join("\n")} vec2 currentPointPx = gl_FragCoord.xy / u_pixelRatio; #ifdef GL_FRAGMENT_PRECISION_HIGH vec2 worldPos = pxToWorld(currentPointPx); if ( abs(u_renderExtent[0] - u_renderExtent[2]) > 0.0 && ( worldPos[0] < u_renderExtent[0] || worldPos[1] < u_renderExtent[1] || worldPos[0] > u_renderExtent[2] || worldPos[1] > u_renderExtent[3] ) ) { discard; } #endif float segmentLengthPx = length(v_segmentEndPx - v_segmentStartPx); segmentLengthPx = max(segmentLengthPx, 1.17549429e-38); // avoid divide by zero vec2 segmentTangent = (v_segmentEndPx - v_segmentStartPx) / segmentLengthPx; vec2 segmentNormal = vec2(-segmentTangent.y, segmentTangent.x); vec2 startToPointPx = currentPointPx - v_segmentStartPx; float lengthToPointPx = max(0., min(dot(segmentTangent, startToPointPx), segmentLengthPx)); float currentLengthPx = lengthToPointPx + v_distancePx; float currentRadiusPx = distanceFromSegment(currentPointPx, v_segmentStartPx, v_segmentEndPx); float currentRadiusRatio = dot(segmentNormal, startToPointPx) * 2. / v_width; currentLineMetric = mix(v_measureStart, v_measureEnd, lengthToPointPx / segmentLengthPx); if (${this.discardExpression_}) { discard; } float capType = ${this.strokeCapExpression_}; float joinType = ${this.strokeJoinExpression_}; float segmentStartDistance = computeSegmentPointDistance(currentPointPx, v_segmentStartPx, v_segmentEndPx, v_width, v_angleStart, capType, joinType); float segmentEndDistance = computeSegmentPointDistance(currentPointPx, v_segmentEndPx, v_segmentStartPx, v_width, v_angleEnd, capType, joinType); float distanceField = max( segmentDistanceField(currentPointPx, v_segmentStartPx, v_segmentEndPx, v_width), max(segmentStartDistance, segmentEndDistance) ); distanceField = max(distanceField, ${this.strokeDistanceFieldExpression_}); vec4 color = ${this.strokeColorExpression_}; color.a *= smoothstep(0.5, -0.5, distanceField); gl_FragColor = color; gl_FragColor.a *= u_globalAlpha; gl_FragColor.rgb *= gl_FragColor.a; if (u_hitDetection > 0) { if (gl_FragColor.a < 0.1) { discard; }; gl_FragColor = v_hitColor; } }`; } /** * Generates a fill vertex shader from the builder parameters * * @return {string|null} The full shader as a string; null if no color specified */ getFillVertexShader() { if (!this.hasFill_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} attribute vec2 a_position; attribute vec2 a_hitColor; varying vec4 v_hitColor; ${this.attributes_.map( (attribute) => `attribute ${attribute.type} ${attribute.name}; varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.vertexShaderFunctions_.join("\n")} void main(void) { gl_Position = u_projectionMatrix * vec4(a_position, u_depth, 1.0); v_hitColor = unpackColor(a_hitColor); ${this.attributes_.map( (attribute) => ` ${attribute.varyingName} = ${attribute.varyingExpression};` ).join("\n")} }`; } /** * Generates a fill fragment shader from the builder parameters * @return {string|null} The full shader as a string; null if no color specified */ getFillFragmentShader() { if (!this.hasFill_) { return null; } return `${COMMON_HEADER} ${this.uniforms_.map((uniform) => `uniform ${uniform.type} ${uniform.name};`).join("\n")} varying vec4 v_hitColor; ${this.attributes_.map( (attribute) => `varying ${attribute.varyingType} ${attribute.varyingName};` ).join("\n")} ${this.fragmentShaderFunctions_.join("\n")} vec2 pxToWorld(vec2 pxPos) { vec2 screenPos = 2.0 * pxPos / u_viewportSizePx - 1.0; return (u_screenToWorldMatrix * vec4(screenPos, 0.0, 1.0)).xy; } vec2 worldToPx(vec2 worldPos) { vec4 screenPos = u_projectionMatrix * vec4(worldPos, 0.0, 1.0); return (0.5 * screenPos.xy + 0.5) * u_viewportSizePx; } void main(void) { ${this.attributes_.map( (attribute) => ` ${attribute.varyingType} ${attribute.name} = ${attribute.varyingName}; // assign to original attribute name` ).join("\n")} vec2 pxPos = gl_FragCoord.xy / u_pixelRatio; vec2 pxOrigin = worldToPx(u_patternOrigin); #ifdef GL_FRAGMENT_PRECISION_HIGH vec2 worldPos = pxToWorld(pxPos); if ( abs(u_renderExtent[0] - u_renderExtent[2]) > 0.0 && ( worldPos[0] < u_renderExtent[0] || worldPos[1] < u_renderExtent[1] || worldPos[0] > u_renderExtent[2] || worldPos[1] > u_renderExtent[3] ) ) { discard; } #endif if (${this.discardExpression_}) { discard; } gl_FragColor = ${this.fillColorExpression_}; gl_FragColor.a *= u_globalAlpha; gl_FragColor.rgb *= gl_FragColor.a; if (u_hitDetection > 0) { if (gl_FragColor.a < 0.1) { discard; }; gl_FragColor = v_hitColor; } }`; } }; // node_modules/ol/render/webgl/MixedGeometryBatch.js var MixedGeometryBatch = class _MixedGeometryBatch { constructor() { this.globalCounter_ = 0; this.refToFeature_ = /* @__PURE__ */ new Map(); this.uidToRef_ = /* @__PURE__ */ new Map(); this.freeGlobalRef_ = []; this.polygonBatch = { entries: {}, geometriesCount: 0, verticesCount: 0, ringsCount: 0 }; this.pointBatch = { entries: {}, geometriesCount: 0 }; this.lineStringBatch = { entries: {}, geometriesCount: 0, verticesCount: 0 }; } /** * @param {Array} features Array of features to add to the batch * @param {import("../../proj.js").TransformFunction} [projectionTransform] Projection transform. */ addFeatures(features, projectionTransform) { for (let i = 0; i < features.length; i++) { this.addFeature(features[i], projectionTransform); } } /** * @param {Feature|RenderFeature} feature Feature to add to the batch * @param {import("../../proj.js").TransformFunction} [projectionTransform] Projection transform. */ addFeature(feature, projectionTransform) { let geometry = feature.getGeometry(); if (!geometry) { return; } if (projectionTransform) { geometry = geometry.clone(); geometry.applyTransform(projectionTransform); } this.addGeometry_(geometry, feature); } /** * @param {Feature|RenderFeature} feature Feature * @return {GeometryBatchItem|void} the cleared entry * @private */ clearFeatureEntryInPointBatch_(feature) { const featureUid = getUid(feature); const entry = this.pointBatch.entries[featureUid]; if (!entry) { return; } this.pointBatch.geometriesCount -= entry.flatCoordss.length; delete this.pointBatch.entries[featureUid]; return entry; } /** * @param {Feature|RenderFeature} feature Feature * @return {GeometryBatchItem|void} the cleared entry * @private */ clearFeatureEntryInLineStringBatch_(feature) { const featureUid = getUid(feature); const entry = this.lineStringBatch.entries[featureUid]; if (!entry) { return; } this.lineStringBatch.verticesCount -= entry.verticesCount; this.lineStringBatch.geometriesCount -= entry.flatCoordss.length; delete this.lineStringBatch.entries[featureUid]; return entry; } /** * @param {Feature|RenderFeature} feature Feature * @return {GeometryBatchItem|void} the cleared entry * @private */ clearFeatureEntryInPolygonBatch_(feature) { const featureUid = getUid(feature); const entry = this.polygonBatch.entries[featureUid]; if (!entry) { return; } this.polygonBatch.verticesCount -= entry.verticesCount; this.polygonBatch.ringsCount -= entry.ringsCount; this.polygonBatch.geometriesCount -= entry.flatCoordss.length; delete this.polygonBatch.entries[featureUid]; return entry; } /** * @param {import("../../geom.js").Geometry|RenderFeature} geometry Geometry * @param {Feature|RenderFeature} feature Feature * @private */ addGeometry_(geometry, feature) { var _a; const type = geometry.getType(); switch (type) { case "GeometryCollection": { const geometries = ( /** @type {import("../../geom.js").GeometryCollection} */ geometry.getGeometriesArray() ); for (const geometry2 of geometries) { this.addGeometry_(geometry2, feature); } break; } case "MultiPolygon": { const multiPolygonGeom = ( /** @type {import("../../geom.js").MultiPolygon} */ geometry ); this.addCoordinates_( type, multiPolygonGeom.getFlatCoordinates(), multiPolygonGeom.getEndss(), feature, getUid(feature), multiPolygonGeom.getStride() ); break; } case "MultiLineString": { const multiLineGeom = ( /** @type {import("../../geom.js").MultiLineString|RenderFeature} */ geometry ); this.addCoordinates_( type, multiLineGeom.getFlatCoordinates(), multiLineGeom.getEnds(), feature, getUid(feature), multiLineGeom.getStride() ); break; } case "MultiPoint": { const multiPointGeom = ( /** @type {import("../../geom.js").MultiPoint|RenderFeature} */ geometry ); this.addCoordinates_( type, multiPointGeom.getFlatCoordinates(), null, feature, getUid(feature), multiPointGeom.getStride() ); break; } case "Polygon": { const polygonGeom = ( /** @type {import("../../geom.js").Polygon|RenderFeature} */ geometry ); this.addCoordinates_( type, polygonGeom.getFlatCoordinates(), polygonGeom.getEnds(), feature, getUid(feature), polygonGeom.getStride() ); break; } case "Point": { const pointGeom = ( /** @type {import("../../geom.js").Point} */ geometry ); this.addCoordinates_( type, pointGeom.getFlatCoordinates(), null, feature, getUid(feature), pointGeom.getStride() ); break; } case "LineString": case "LinearRing": { const lineGeom = ( /** @type {import("../../geom.js").LineString} */ geometry ); const stride = lineGeom.getStride(); this.addCoordinates_( type, lineGeom.getFlatCoordinates(), null, feature, getUid(feature), stride, (_a = lineGeom.getLayout) == null ? void 0 : _a.call(lineGeom) ); break; } default: } } /** * @param {GeometryType} type Geometry type * @param {Array} flatCoords Flat coordinates * @param {Array | Array> | null} ends Coordinate ends * @param {Feature|RenderFeature} feature Feature * @param {string} featureUid Feature uid * @param {number} stride Stride * @param {import('../../geom/Geometry.js').GeometryLayout} [layout] Layout * @private */ addCoordinates_(type, flatCoords, ends, feature, featureUid, stride, layout) { let verticesCount; switch (type) { case "MultiPolygon": { const multiPolygonEndss = ( /** @type {Array>} */ ends ); for (let i = 0, ii = multiPolygonEndss.length; i < ii; i++) { let polygonEnds = multiPolygonEndss[i]; const prevPolygonEnds = i > 0 ? multiPolygonEndss[i - 1] : null; const startIndex = prevPolygonEnds ? prevPolygonEnds[prevPolygonEnds.length - 1] : 0; const endIndex = polygonEnds[polygonEnds.length - 1]; polygonEnds = startIndex > 0 ? polygonEnds.map((end) => end - startIndex) : polygonEnds; this.addCoordinates_( "Polygon", flatCoords.slice(startIndex, endIndex), polygonEnds, feature, featureUid, stride, layout ); } break; } case "MultiLineString": { const multiLineEnds = ( /** @type {Array} */ ends ); for (let i = 0, ii = multiLineEnds.length; i < ii; i++) { const startIndex = i > 0 ? multiLineEnds[i - 1] : 0; this.addCoordinates_( "LineString", flatCoords.slice(startIndex, multiLineEnds[i]), null, feature, featureUid, stride, layout ); } break; } case "MultiPoint": for (let i = 0, ii = flatCoords.length; i < ii; i += stride) { this.addCoordinates_( "Point", flatCoords.slice(i, i + 2), null, feature, featureUid, null, null ); } break; case "Polygon": { const polygonEnds = ( /** @type {Array} */ ends ); if (feature instanceof Feature_default) { const multiPolygonEnds = inflateEnds(flatCoords, polygonEnds); if (multiPolygonEnds.length > 1) { this.addCoordinates_( "MultiPolygon", flatCoords, multiPolygonEnds, feature, featureUid, stride, layout ); return; } } if (!this.polygonBatch.entries[featureUid]) { this.polygonBatch.entries[featureUid] = this.addRefToEntry_( featureUid, { feature, flatCoordss: [], verticesCount: 0, ringsCount: 0, ringsVerticesCounts: [] } ); } verticesCount = flatCoords.length / stride; const ringsCount = ends.length; const ringsVerticesCount = ends.map( (end, ind, arr) => ind > 0 ? (end - arr[ind - 1]) / stride : end / stride ); this.polygonBatch.verticesCount += verticesCount; this.polygonBatch.ringsCount += ringsCount; this.polygonBatch.geometriesCount++; this.polygonBatch.entries[featureUid].flatCoordss.push( getFlatCoordinatesXY(flatCoords, stride) ); this.polygonBatch.entries[featureUid].ringsVerticesCounts.push( ringsVerticesCount ); this.polygonBatch.entries[featureUid].verticesCount += verticesCount; this.polygonBatch.entries[featureUid].ringsCount += ringsCount; for (let i = 0, ii = polygonEnds.length; i < ii; i++) { const startIndex = i > 0 ? polygonEnds[i - 1] : 0; this.addCoordinates_( "LinearRing", flatCoords.slice(startIndex, polygonEnds[i]), null, feature, featureUid, stride, layout ); } break; } case "Point": if (!this.pointBatch.entries[featureUid]) { this.pointBatch.entries[featureUid] = this.addRefToEntry_( featureUid, { feature, flatCoordss: [] } ); } this.pointBatch.geometriesCount++; this.pointBatch.entries[featureUid].flatCoordss.push(flatCoords); break; case "LineString": case "LinearRing": if (!this.lineStringBatch.entries[featureUid]) { this.lineStringBatch.entries[featureUid] = this.addRefToEntry_( featureUid, { feature, flatCoordss: [], verticesCount: 0 } ); } verticesCount = flatCoords.length / stride; this.lineStringBatch.verticesCount += verticesCount; this.lineStringBatch.geometriesCount++; this.lineStringBatch.entries[featureUid].flatCoordss.push( getFlatCoordinatesXYM(flatCoords, stride, layout) ); this.lineStringBatch.entries[featureUid].verticesCount += verticesCount; break; default: } } /** * @param {string} featureUid Feature uid * @param {GeometryBatchItem} entry The entry to add * @return {GeometryBatchItem} the added entry * @private */ addRefToEntry_(featureUid, entry) { const currentRef = this.uidToRef_.get(featureUid); const ref = currentRef || this.freeGlobalRef_.pop() || ++this.globalCounter_; entry.ref = ref; if (!currentRef) { this.refToFeature_.set(ref, entry.feature); this.uidToRef_.set(featureUid, ref); } return entry; } /** * Return a ref to the pool of available refs. * @param {number} ref the ref to return * @param {string} featureUid the feature uid * @private */ removeRef_(ref, featureUid) { if (!ref) { throw new Error("This feature has no ref: " + featureUid); } this.refToFeature_.delete(ref); this.uidToRef_.delete(featureUid); this.freeGlobalRef_.push(ref); } /** * @param {Feature|RenderFeature} feature Feature * @param {import("../../proj.js").TransformFunction} [projectionTransform] Projection transform. */ changeFeature(feature, projectionTransform) { if (!this.uidToRef_.get(getUid(feature))) { return; } this.removeFeature(feature); let geometry = feature.getGeometry(); if (!geometry) { return; } if (projectionTransform) { geometry = geometry.clone(); geometry.applyTransform(projectionTransform); } this.addGeometry_(geometry, feature); } /** * @param {Feature|RenderFeature} feature Feature */ removeFeature(feature) { let entry = this.clearFeatureEntryInPointBatch_(feature); entry = this.clearFeatureEntryInPolygonBatch_(feature) || entry; entry = this.clearFeatureEntryInLineStringBatch_(feature) || entry; if (entry) { this.removeRef_(entry.ref, getUid(entry.feature)); } } clear() { this.polygonBatch.entries = {}; this.polygonBatch.geometriesCount = 0; this.polygonBatch.verticesCount = 0; this.polygonBatch.ringsCount = 0; this.lineStringBatch.entries = {}; this.lineStringBatch.geometriesCount = 0; this.lineStringBatch.verticesCount = 0; this.pointBatch.entries = {}; this.pointBatch.geometriesCount = 0; this.globalCounter_ = 0; this.freeGlobalRef_ = []; this.refToFeature_.clear(); this.uidToRef_.clear(); } /** * Resolve the feature associated to a ref. * @param {number} ref Hit detected ref * @return {Feature|RenderFeature} feature */ getFeatureFromRef(ref) { return this.refToFeature_.get(ref); } isEmpty() { return this.globalCounter_ === 0; } /** * Will return a new instance of this class that only contains the features * for which the provided callback returned true * @param {function((Feature|RenderFeature)): boolean} featureFilter Feature filter callback * @return {MixedGeometryBatch} Filtered geometry batch */ filter(featureFilter) { const filtered = new _MixedGeometryBatch(); filtered.globalCounter_ = this.globalCounter_; filtered.uidToRef_ = this.uidToRef_; filtered.refToFeature_ = this.refToFeature_; let empty = true; for (const feature of this.refToFeature_.values()) { if (featureFilter(feature)) { filtered.addFeature(feature); empty = false; } } if (empty) { return new _MixedGeometryBatch(); } return filtered; } }; function getFlatCoordinatesXY(flatCoords, stride) { if (stride === 2) { return flatCoords; } return flatCoords.filter((v, i) => i % stride < 2); } function getFlatCoordinatesXYM(flatCoords, stride, layout) { if (stride === 3 && layout === "XYM") { return flatCoords; } if (stride === 4) { return flatCoords.filter((v, i) => i % stride !== 2); } if (stride === 3) { return flatCoords.map((v, i) => i % stride !== 2 ? v : 0); } return new Array(flatCoords.length * 1.5).fill(0).map((v, i) => i % 3 === 2 ? 0 : flatCoords[Math.round(i / 1.5)]); } var MixedGeometryBatch_default = MixedGeometryBatch; // node_modules/ol/worker/webgl.js function create3() { const source = 'function t(t,n,x=2){const o=n&&n.length,i=o?n[0]*x:t.length;let f=e(t,0,i,x,!0);const l=[];if(!f||f.next===f.prev)return l;let c,y,h;if(o&&(f=function(t,n,r,x){const o=[];for(let r=0,i=n.length;r80*x){c=t[0],y=t[1];let e=c,n=y;for(let r=x;re&&(e=x),o>n&&(n=o)}h=Math.max(e-c,n-y),h=0!==h?32767/h:0}return r(f,l,x,c,y,h,0),l}function e(t,e,n,r,x){let o;if(x===function(t,e,n,r){let x=0;for(let o=e,i=n-r;o0)for(let x=e;x=e;x-=r)o=d(x/r|0,t[x],t[x+1],o);return o&&b(o,o.next)&&(w(o),o=o.next),o}function n(t,e){if(!t)return t;e||(e=t);let n,r=t;do{if(n=!1,r.steiner||!b(r,r.next)&&0!==v(r.prev,r,r.next))r=r.next;else{if(w(r),r=e=r.prev,r===r.next)break;n=!0}}while(n||r!==e);return e}function r(t,e,u,s,l,a,y){if(!t)return;!y&&a&&function(t,e,n,r){let x=t;do{0===x.z&&(x.z=c(x.x,x.y,e,n,r)),x.prevZ=x.prev,x.nextZ=x.next,x=x.next}while(x!==t);x.prevZ.nextZ=null,x.prevZ=null,function(t){let e,n=1;do{let r,x=t;t=null;let o=null;for(e=0;x;){e++;let i=x,f=0;for(let t=0;t0||u>0&&i;)0!==f&&(0===u||!i||x.z<=i.z)?(r=x,x=x.nextZ,f--):(r=i,i=i.nextZ,u--),o?o.nextZ=r:t=r,r.prevZ=o,o=r;x=i}o.nextZ=null,n*=2}while(e>1)}(x)}(t,s,l,a);let h=t;for(;t.prev!==t.next;){const c=t.prev,p=t.next;if(a?o(t,s,l,a):x(t))e.push(c.i,t.i,p.i),w(t),t=p.next,h=p.next;else if((t=p)===h){y?1===y?r(t=i(n(t),e),e,u,s,l,a,2):2===y&&f(t,e,u,s,l,a):r(n(t),e,u,s,l,a,1);break}}}function x(t){const e=t.prev,n=t,r=t.next;if(v(e,n,r)>=0)return!1;const x=e.x,o=n.x,i=r.x,f=e.y,u=n.y,s=r.y,l=Math.min(x,o,i),c=Math.min(f,u,s),a=Math.max(x,o,i),y=Math.max(f,u,s);let p=r.next;for(;p!==e;){if(p.x>=l&&p.x<=a&&p.y>=c&&p.y<=y&&h(x,f,o,u,i,s,p.x,p.y)&&v(p.prev,p,p.next)>=0)return!1;p=p.next}return!0}function o(t,e,n,r){const x=t.prev,o=t,i=t.next;if(v(x,o,i)>=0)return!1;const f=x.x,u=o.x,s=i.x,l=x.y,a=o.y,y=i.y,p=Math.min(f,u,s),b=Math.min(l,a,y),M=Math.max(f,u,s),m=Math.max(l,a,y),A=c(p,b,e,n,r),g=c(M,m,e,n,r);let Z=t.prevZ,d=t.nextZ;for(;Z&&Z.z>=A&&d&&d.z<=g;){if(Z.x>=p&&Z.x<=M&&Z.y>=b&&Z.y<=m&&Z!==x&&Z!==i&&h(f,l,u,a,s,y,Z.x,Z.y)&&v(Z.prev,Z,Z.next)>=0)return!1;if(Z=Z.prevZ,d.x>=p&&d.x<=M&&d.y>=b&&d.y<=m&&d!==x&&d!==i&&h(f,l,u,a,s,y,d.x,d.y)&&v(d.prev,d,d.next)>=0)return!1;d=d.nextZ}for(;Z&&Z.z>=A;){if(Z.x>=p&&Z.x<=M&&Z.y>=b&&Z.y<=m&&Z!==x&&Z!==i&&h(f,l,u,a,s,y,Z.x,Z.y)&&v(Z.prev,Z,Z.next)>=0)return!1;Z=Z.prevZ}for(;d&&d.z<=g;){if(d.x>=p&&d.x<=M&&d.y>=b&&d.y<=m&&d!==x&&d!==i&&h(f,l,u,a,s,y,d.x,d.y)&&v(d.prev,d,d.next)>=0)return!1;d=d.nextZ}return!0}function i(t,e){let r=t;do{const n=r.prev,x=r.next.next;!b(n,x)&&M(n,r,r.next,x)&&g(n,x)&&g(x,n)&&(e.push(n.i,r.i,x.i),w(r),w(r.next),r=t=x),r=r.next}while(r!==t);return n(r)}function f(t,e,x,o,i,f){let u=t;do{let t=u.next.next;for(;t!==u.prev;){if(u.i!==t.i&&p(u,t)){let s=Z(u,t);return u=n(u,u.next),s=n(s,s.next),r(u,e,x,o,i,f,0),void r(s,e,x,o,i,f,0)}t=t.next}u=u.next}while(u!==t)}function u(t,e){let n=t.x-e.x;if(0===n&&(n=t.y-e.y,0===n)){n=(t.next.y-t.y)/(t.next.x-t.x)-(e.next.y-e.y)/(e.next.x-e.x)}return n}function s(t,e){const r=function(t,e){let n=e;const r=t.x,x=t.y;let o,i=-1/0;if(b(t,n))return n;do{if(b(t,n.next))return n.next;if(x<=n.y&&x>=n.next.y&&n.next.y!==n.y){const t=n.x+(x-n.y)*(n.next.x-n.x)/(n.next.y-n.y);if(t<=r&&t>i&&(i=t,o=n.x=n.x&&n.x>=u&&r!==n.x&&y(xo.x||n.x===o.x&&l(o,n)))&&(o=n,c=e)}n=n.next}while(n!==f);return o}(t,e);if(!r)return e;const x=Z(r,t);return n(x,x.next),n(r,r.next)}function l(t,e){return v(t.prev,t,e.prev)<0&&v(e.next,t,t.next)<0}function c(t,e,n,r,x){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-n)*x|0)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-r)*x|0)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function a(t){let e=t,n=t;do{(e.x=(t-i)*(o-f)&&(t-i)*(r-f)>=(n-i)*(e-f)&&(n-i)*(o-f)>=(x-i)*(r-f)}function h(t,e,n,r,x,o,i,f){return!(t===i&&e===f)&&y(t,e,n,r,x,o,i,f)}function p(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let n=t;do{if(n.i!==t.i&&n.next.i!==t.i&&n.i!==e.i&&n.next.i!==e.i&&M(n,n.next,t,e))return!0;n=n.next}while(n!==t);return!1}(t,e)&&(g(t,e)&&g(e,t)&&function(t,e){let n=t,r=!1;const x=(t.x+e.x)/2,o=(t.y+e.y)/2;do{n.y>o!=n.next.y>o&&n.next.y!==n.y&&x<(n.next.x-n.x)*(o-n.y)/(n.next.y-n.y)+n.x&&(r=!r),n=n.next}while(n!==t);return r}(t,e)&&(v(t.prev,t,e.prev)||v(t,e.prev,e))||b(t,e)&&v(t.prev,t,t.next)>0&&v(e.prev,e,e.next)>0)}function v(t,e,n){return(e.y-t.y)*(n.x-e.x)-(e.x-t.x)*(n.y-e.y)}function b(t,e){return t.x===e.x&&t.y===e.y}function M(t,e,n,r){const x=A(v(t,e,n)),o=A(v(t,e,r)),i=A(v(n,r,t)),f=A(v(n,r,e));return x!==o&&i!==f||(!(0!==x||!m(t,n,e))||(!(0!==o||!m(t,r,e))||(!(0!==i||!m(n,t,r))||!(0!==f||!m(n,e,r)))))}function m(t,e,n){return e.x<=Math.max(t.x,n.x)&&e.x>=Math.min(t.x,n.x)&&e.y<=Math.max(t.y,n.y)&&e.y>=Math.min(t.y,n.y)}function A(t){return t>0?1:t<0?-1:0}function g(t,e){return v(t.prev,t,t.next)<0?v(t,e,t.next)>=0&&v(t,t.prev,e)>=0:v(t,e,t.prev)<0||v(t,t.next,e)<0}function Z(t,e){const n=F(t.i,t.x,t.y),r=F(e.i,e.x,e.y),x=t.next,o=e.prev;return t.next=e,e.prev=t,n.next=x,x.prev=n,r.next=n,n.prev=r,o.next=r,r.prev=o,r}function d(t,e,n,r){const x=F(t,e,n);return r?(x.next=r.next,x.prev=r,r.next.prev=x,r.next=x):(x.prev=x,x.next=x),x}function w(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function F(t,e,n){return{i:t,x:e,y:n,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}function E(t,e){const n=e[0],r=e[1];return e[0]=t[0]*n+t[2]*r+t[4],e[1]=t[1]*n+t[3]*r+t[5],e}function I(t,e){const n=(r=e)[0]*r[3]-r[1]*r[2];var r;!function(t,e){if(!t)throw new Error(e)}(0!==n,"Transformation matrix cannot be inverted");const x=e[0],o=e[1],i=e[2],f=e[3],u=e[4],s=e[5];return t[0]=f/n,t[1]=-o/n,t[2]=-i/n,t[3]=x/n,t[4]=(i*s-f*u)/n,t[5]=-(x*s-o*u)/n,t}new Array(6);const z=[],B={vertexAttributesPosition:0,instanceAttributesPosition:0,indicesPosition:0};function P(t,e,n,r,x){const o=t[e++],i=t[e++],f=z;f.length=r;for(let n=0;n0?u:2*Math.PI-u}let b=-1,M=-1,m=s;const A=null!==x;if(null!==r){b=v(h,p,E(f,[...[t[r],t[r+1]]])),Math.cos(b)<=.985&&(m+=Math.tan((b-Math.PI)/2))}if(A){M=v(p,h,E(f,[...[t[x],t[x+1]]])),Math.cos(M)<=.985&&(m+=Math.tan((Math.PI-M)/2))}const g=Math.pow(2,24),Z=u%g,d=Math.floor(u/g)*g;return o.push(l[0],l[1],a,c[0],c[1],y,b,M,Z,d,s),o.push(...i),{length:u+Math.sqrt((p[0]-h[0])*(p[0]-h[0])+(p[1]-h[1])*(p[1]-h[1])),angle:m}}function R(e,n,r,x,o){const i=2+o;let f=n;const u=e.slice(f,f+o);f+=o;const s=e[f++];let l=0;const c=new Array(s-1);for(let t=0;t{const e=t.data;switch(e.type){case T:{const t=2,n=2,r=e.customAttributesSize,x=n+r,o=new Float32Array(e.renderInstructions),i=o.length/x*(t+r),f=Uint32Array.from([0,1,3,1,2,3]),u=Float32Array.from([-1,-1,1,-1,1,1,-1,1]),s=new Float32Array(i);let l;for(let t=0;t0?y=o+(n-1)*r:l&&(y=s-r);let h=null;n prev + (customAttributes[curr].size || 1), 0 ); } function generatePointRenderInstructions(batch, renderInstructions, customAttributes, transform) { const totalInstructionsCount = (2 + getCustomAttributesSize(customAttributes)) * batch.geometriesCount; if (!renderInstructions || renderInstructions.length !== totalInstructionsCount) { renderInstructions = new Float32Array(totalInstructionsCount); } const tmpCoords = []; let renderIndex = 0; for (const featureUid in batch.entries) { const batchEntry = batch.entries[featureUid]; for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) { tmpCoords[0] = batchEntry.flatCoordss[i][0]; tmpCoords[1] = batchEntry.flatCoordss[i][1]; apply(transform, tmpCoords); renderInstructions[renderIndex++] = tmpCoords[0]; renderInstructions[renderIndex++] = tmpCoords[1]; renderIndex += pushCustomAttributesInRenderInstructions( renderInstructions, customAttributes, batchEntry, renderIndex ); } } return renderInstructions; } function generateLineStringRenderInstructions(batch, renderInstructions, customAttributes, transform) { const totalInstructionsCount = 3 * batch.verticesCount + (1 + getCustomAttributesSize(customAttributes)) * batch.geometriesCount; if (!renderInstructions || renderInstructions.length !== totalInstructionsCount) { renderInstructions = new Float32Array(totalInstructionsCount); } const flatCoords = []; let renderIndex = 0; for (const featureUid in batch.entries) { const batchEntry = batch.entries[featureUid]; for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) { flatCoords.length = batchEntry.flatCoordss[i].length; transform2D( batchEntry.flatCoordss[i], 0, flatCoords.length, 3, transform, flatCoords, 3 ); renderIndex += pushCustomAttributesInRenderInstructions( renderInstructions, customAttributes, batchEntry, renderIndex ); renderInstructions[renderIndex++] = flatCoords.length / 3; for (let j = 0, jj = flatCoords.length; j < jj; j += 3) { renderInstructions[renderIndex++] = flatCoords[j]; renderInstructions[renderIndex++] = flatCoords[j + 1]; renderInstructions[renderIndex++] = flatCoords[j + 2]; } } } return renderInstructions; } function generatePolygonRenderInstructions(batch, renderInstructions, customAttributes, transform) { const totalInstructionsCount = 2 * batch.verticesCount + (1 + getCustomAttributesSize(customAttributes)) * batch.geometriesCount + batch.ringsCount; if (!renderInstructions || renderInstructions.length !== totalInstructionsCount) { renderInstructions = new Float32Array(totalInstructionsCount); } const flatCoords = []; let renderIndex = 0; for (const featureUid in batch.entries) { const batchEntry = batch.entries[featureUid]; for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) { flatCoords.length = batchEntry.flatCoordss[i].length; transform2D( batchEntry.flatCoordss[i], 0, flatCoords.length, 2, transform, flatCoords ); renderIndex += pushCustomAttributesInRenderInstructions( renderInstructions, customAttributes, batchEntry, renderIndex ); renderInstructions[renderIndex++] = batchEntry.ringsVerticesCounts[i].length; for (let j = 0, jj = batchEntry.ringsVerticesCounts[i].length; j < jj; j++) { renderInstructions[renderIndex++] = batchEntry.ringsVerticesCounts[i][j]; } for (let j = 0, jj = flatCoords.length; j < jj; j += 2) { renderInstructions[renderIndex++] = flatCoords[j]; renderInstructions[renderIndex++] = flatCoords[j + 1]; } } } return renderInstructions; } // node_modules/ol/render/webgl/style.js function computeHash(input) { const hash = JSON.stringify(input).split("").reduce((prev, curr) => (prev << 5) - prev + curr.charCodeAt(0), 0); return (hash >>> 0).toString(); } function parseCommonSymbolProperties(style, builder, vertContext, prefix) { if (`${prefix}radius` in style && prefix !== "icon-") { let radius = expressionToGlsl( vertContext, style[`${prefix}radius`], NumberType ); if (`${prefix}radius2` in style) { const radius2 = expressionToGlsl( vertContext, style[`${prefix}radius2`], NumberType ); radius = `max(${radius}, ${radius2})`; } if (`${prefix}stroke-width` in style) { radius = `(${radius} + ${expressionToGlsl( vertContext, style[`${prefix}stroke-width`], NumberType )} * 0.5)`; } builder.setSymbolSizeExpression(`vec2(${radius} * 2. + 0.5)`); } if (`${prefix}scale` in style) { const scale2 = expressionToGlsl( vertContext, style[`${prefix}scale`], SizeType ); builder.setSymbolSizeExpression( `${builder.getSymbolSizeExpression()} * ${scale2}` ); } if (`${prefix}displacement` in style) { builder.setSymbolOffsetExpression( expressionToGlsl( vertContext, style[`${prefix}displacement`], NumberArrayType ) ); } if (`${prefix}rotation` in style) { builder.setSymbolRotationExpression( expressionToGlsl(vertContext, style[`${prefix}rotation`], NumberType) ); } if (`${prefix}rotate-with-view` in style) { builder.setSymbolRotateWithView(!!style[`${prefix}rotate-with-view`]); } } function getColorFromDistanceField(distanceField, fillColor, strokeColor, strokeWidth, opacity) { let color = "vec4(0.)"; if (fillColor !== null) { color = fillColor; } if (strokeColor !== null && strokeWidth !== null) { const strokeFillRatio = `smoothstep(-${strokeWidth} + 0.63, -${strokeWidth} - 0.58, ${distanceField})`; color = `mix(${strokeColor}, ${color}, ${strokeFillRatio})`; } const shapeOpacity = `(1.0 - smoothstep(-0.63, 0.58, ${distanceField}))`; let result = `${color} * vec4(1.0, 1.0, 1.0, ${shapeOpacity})`; if (opacity !== null) { result = `${result} * vec4(1.0, 1.0, 1.0, ${opacity})`; } return result; } function parseImageProperties(style, builder, uniforms, prefix, textureId) { const image = new Image(); image.crossOrigin = style[`${prefix}cross-origin`] === void 0 ? "anonymous" : style[`${prefix}cross-origin`]; assert( typeof style[`${prefix}src`] === "string", `WebGL layers do not support expressions for the ${prefix}src style property` ); image.src = /** @type {string} */ style[`${prefix}src`]; uniforms[`u_texture${textureId}_size`] = () => { return image.complete ? [image.width, image.height] : [0, 0]; }; builder.addUniform(`u_texture${textureId}_size`, "vec2"); const size = `u_texture${textureId}_size`; uniforms[`u_texture${textureId}`] = image; builder.addUniform(`u_texture${textureId}`, "sampler2D"); return size; } function parseImageOffsetProperties(style, prefix, context, imageSize, sampleSize) { let offsetExpression = expressionToGlsl( context, style[`${prefix}offset`], SizeType ); if (`${prefix}offset-origin` in style) { switch (style[`${prefix}offset-origin`]) { case "top-right": offsetExpression = `vec2(${imageSize}.x, 0.) + ${sampleSize} * vec2(-1., 0.) + ${offsetExpression} * vec2(-1., 1.)`; break; case "bottom-left": offsetExpression = `vec2(0., ${imageSize}.y) + ${sampleSize} * vec2(0., -1.) + ${offsetExpression} * vec2(1., -1.)`; break; case "bottom-right": offsetExpression = `${imageSize} - ${sampleSize} - ${offsetExpression}`; break; default: } } return offsetExpression; } function parseCircleProperties(style, builder, uniforms, context) { context.functions["circleDistanceField"] = `float circleDistanceField(vec2 point, float radius) { return length(point) - radius; }`; parseCommonSymbolProperties(style, builder, context, "circle-"); let opacity = null; if ("circle-opacity" in style) { opacity = expressionToGlsl(context, style["circle-opacity"], NumberType); } let currentPoint = "coordsPx"; if ("circle-scale" in style) { const scale2 = expressionToGlsl(context, style["circle-scale"], SizeType); currentPoint = `coordsPx / ${scale2}`; } let fillColor = null; if ("circle-fill-color" in style) { fillColor = expressionToGlsl( context, style["circle-fill-color"], ColorType ); } let strokeColor = null; if ("circle-stroke-color" in style) { strokeColor = expressionToGlsl( context, style["circle-stroke-color"], ColorType ); } let radius = expressionToGlsl(context, style["circle-radius"], NumberType); let strokeWidth = null; if ("circle-stroke-width" in style) { strokeWidth = expressionToGlsl( context, style["circle-stroke-width"], NumberType ); radius = `(${radius} + ${strokeWidth} * 0.5)`; } const distanceField = `circleDistanceField(${currentPoint}, ${radius})`; const colorExpression = getColorFromDistanceField( distanceField, fillColor, strokeColor, strokeWidth, opacity ); builder.setSymbolColorExpression(colorExpression); } function parseShapeProperties(style, builder, uniforms, context) { context.functions["round"] = `float round(float v) { return sign(v) * floor(abs(v) + 0.5); }`; context.functions["starDistanceField"] = `float starDistanceField(vec2 point, float numPoints, float radius, float radius2, float angle) { float startAngle = -PI * 0.5 + angle; // tip starts upwards and rotates clockwise with angle float c = cos(startAngle); float s = sin(startAngle); vec2 pointRotated = vec2(c * point.x - s * point.y, s * point.x + c * point.y); float alpha = TWO_PI / numPoints; // the angle of one sector float beta = atan(pointRotated.y, pointRotated.x); float gamma = round(beta / alpha) * alpha; // angle in sector c = cos(-gamma); s = sin(-gamma); vec2 inSector = vec2(c * pointRotated.x - s * pointRotated.y, abs(s * pointRotated.x + c * pointRotated.y)); vec2 tipToPoint = inSector + vec2(-radius, 0.); vec2 edgeNormal = vec2(radius2 * sin(alpha * 0.5), -radius2 * cos(alpha * 0.5) + radius); return dot(normalize(edgeNormal), tipToPoint); }`; context.functions["regularDistanceField"] = `float regularDistanceField(vec2 point, float numPoints, float radius, float angle) { float startAngle = -PI * 0.5 + angle; // tip starts upwards and rotates clockwise with angle float c = cos(startAngle); float s = sin(startAngle); vec2 pointRotated = vec2(c * point.x - s * point.y, s * point.x + c * point.y); float alpha = TWO_PI / numPoints; // the angle of one sector float radiusIn = radius * cos(PI / numPoints); float beta = atan(pointRotated.y, pointRotated.x); float gamma = round((beta - alpha * 0.5) / alpha) * alpha + alpha * 0.5; // angle in sector from mid c = cos(-gamma); s = sin(-gamma); vec2 inSector = vec2(c * pointRotated.x - s * pointRotated.y, abs(s * pointRotated.x + c * pointRotated.y)); return inSector.x - radiusIn; }`; parseCommonSymbolProperties(style, builder, context, "shape-"); let opacity = null; if ("shape-opacity" in style) { opacity = expressionToGlsl(context, style["shape-opacity"], NumberType); } let currentPoint = "coordsPx"; if ("shape-scale" in style) { const scale2 = expressionToGlsl(context, style["shape-scale"], SizeType); currentPoint = `coordsPx / ${scale2}`; } let fillColor = null; if ("shape-fill-color" in style) { fillColor = expressionToGlsl(context, style["shape-fill-color"], ColorType); } let strokeColor = null; if ("shape-stroke-color" in style) { strokeColor = expressionToGlsl( context, style["shape-stroke-color"], ColorType ); } let strokeWidth = null; if ("shape-stroke-width" in style) { strokeWidth = expressionToGlsl( context, style["shape-stroke-width"], NumberType ); } const numPoints = expressionToGlsl( context, style["shape-points"], NumberType ); let angle = "0."; if ("shape-angle" in style) { angle = expressionToGlsl(context, style["shape-angle"], NumberType); } let shapeField; let radius = expressionToGlsl(context, style["shape-radius"], NumberType); if (strokeWidth !== null) { radius = `${radius} + ${strokeWidth} * 0.5`; } if ("shape-radius2" in style) { let radius2 = expressionToGlsl(context, style["shape-radius2"], NumberType); if (strokeWidth !== null) { radius2 = `${radius2} + ${strokeWidth} * 0.5`; } shapeField = `starDistanceField(${currentPoint}, ${numPoints}, ${radius}, ${radius2}, ${angle})`; } else { shapeField = `regularDistanceField(${currentPoint}, ${numPoints}, ${radius}, ${angle})`; } const colorExpression = getColorFromDistanceField( shapeField, fillColor, strokeColor, strokeWidth, opacity ); builder.setSymbolColorExpression(colorExpression); } function parseIconProperties(style, builder, uniforms, context) { let color = "vec4(1.0)"; if ("icon-color" in style) { color = expressionToGlsl(context, style["icon-color"], ColorType); } if ("icon-opacity" in style) { color = `${color} * vec4(1.0, 1.0, 1.0, ${expressionToGlsl( context, style["icon-opacity"], NumberType )})`; } const textureId = computeHash(style["icon-src"]); const sizeExpression = parseImageProperties( style, builder, uniforms, "icon-", textureId ); builder.setSymbolColorExpression( `${color} * texture2D(u_texture${textureId}, v_texCoord)` ).setSymbolSizeExpression(sizeExpression); if ("icon-width" in style && "icon-height" in style) { builder.setSymbolSizeExpression( `vec2(${expressionToGlsl( context, style["icon-width"], NumberType )}, ${expressionToGlsl(context, style["icon-height"], NumberType)})` ); } if ("icon-offset" in style && "icon-size" in style) { const sampleSize = expressionToGlsl( context, style["icon-size"], NumberArrayType ); const fullsize = builder.getSymbolSizeExpression(); builder.setSymbolSizeExpression(sampleSize); const offset = parseImageOffsetProperties( style, "icon-", context, "v_quadSizePx", sampleSize ); builder.setTextureCoordinateExpression( `(vec4((${offset}).xyxy) + vec4(0., 0., ${sampleSize})) / (${fullsize}).xyxy` ); } parseCommonSymbolProperties(style, builder, context, "icon-"); if ("icon-anchor" in style) { const anchor = expressionToGlsl( context, style["icon-anchor"], NumberArrayType ); let scale2 = `1.0`; if (`icon-scale` in style) { scale2 = expressionToGlsl(context, style[`icon-scale`], SizeType); } let shiftPx; if (style["icon-anchor-x-units"] === "pixels" && style["icon-anchor-y-units"] === "pixels") { shiftPx = `${anchor} * ${scale2}`; } else if (style["icon-anchor-x-units"] === "pixels") { shiftPx = `${anchor} * vec2(vec2(${scale2}).x, v_quadSizePx.y)`; } else if (style["icon-anchor-y-units"] === "pixels") { shiftPx = `${anchor} * vec2(v_quadSizePx.x, vec2(${scale2}).x)`; } else { shiftPx = `${anchor} * v_quadSizePx`; } let offsetPx = `v_quadSizePx * vec2(0.5, -0.5) + ${shiftPx} * vec2(-1., 1.)`; if ("icon-anchor-origin" in style) { switch (style["icon-anchor-origin"]) { case "top-right": offsetPx = `v_quadSizePx * -0.5 + ${shiftPx}`; break; case "bottom-left": offsetPx = `v_quadSizePx * 0.5 - ${shiftPx}`; break; case "bottom-right": offsetPx = `v_quadSizePx * vec2(-0.5, 0.5) + ${shiftPx} * vec2(1., -1.)`; break; default: } } builder.setSymbolOffsetExpression( `${builder.getSymbolOffsetExpression()} + ${offsetPx}` ); } } function parseStrokeProperties(style, builder, uniforms, context) { if ("stroke-color" in style) { builder.setStrokeColorExpression( expressionToGlsl(context, style["stroke-color"], ColorType) ); } if ("stroke-pattern-src" in style) { const textureId = computeHash(style["stroke-pattern-src"]); const sizeExpression = parseImageProperties( style, builder, uniforms, "stroke-pattern-", textureId ); let sampleSizeExpression = sizeExpression; let offsetExpression = "vec2(0.)"; if ("stroke-pattern-offset" in style && "stroke-pattern-size" in style) { sampleSizeExpression = expressionToGlsl( context, style[`stroke-pattern-size`], NumberArrayType ); offsetExpression = parseImageOffsetProperties( style, "stroke-pattern-", context, sizeExpression, sampleSizeExpression ); } let spacingExpression = "0."; if ("stroke-pattern-spacing" in style) { spacingExpression = expressionToGlsl( context, style["stroke-pattern-spacing"], NumberType ); } let startOffsetExpression = "0."; if ("stroke-pattern-start-offset" in style) { startOffsetExpression = expressionToGlsl( context, style["stroke-pattern-start-offset"], NumberType ); } context.functions["sampleStrokePattern"] = `vec4 sampleStrokePattern(sampler2D texture, vec2 textureSize, vec2 textureOffset, vec2 sampleSize, float spacingPx, float startOffsetPx, float currentLengthPx, float currentRadiusRatio, float lineWidth) { float currentLengthScaled = (currentLengthPx - startOffsetPx) * sampleSize.y / lineWidth; float spacingScaled = spacingPx * sampleSize.y / lineWidth; float uCoordPx = mod(currentLengthScaled, (sampleSize.x + spacingScaled)); float isInsideOfPattern = step(uCoordPx, sampleSize.x); float vCoordPx = (-currentRadiusRatio * 0.5 + 0.5) * sampleSize.y; // make sure that we're not sampling too close to the borders to avoid interpolation with outside pixels uCoordPx = clamp(uCoordPx, 0.5, sampleSize.x - 0.5); vCoordPx = clamp(vCoordPx, 0.5, sampleSize.y - 0.5); vec2 texCoord = (vec2(uCoordPx, vCoordPx) + textureOffset) / textureSize; return texture2D(texture, texCoord) * vec4(1.0, 1.0, 1.0, isInsideOfPattern); }`; const textureName = `u_texture${textureId}`; let tintExpression = "1."; if ("stroke-color" in style) { tintExpression = builder.getStrokeColorExpression(); } builder.setStrokeColorExpression( `${tintExpression} * sampleStrokePattern(${textureName}, ${sizeExpression}, ${offsetExpression}, ${sampleSizeExpression}, ${spacingExpression}, ${startOffsetExpression}, currentLengthPx, currentRadiusRatio, v_width)` ); context.functions["computeStrokePatternLength"] = `float computeStrokePatternLength(vec2 sampleSize, float spacingPx, float lineWidth) { float patternLengthPx = sampleSize.x / sampleSize.y * lineWidth; return patternLengthPx + spacingPx; }`; builder.setStrokePatternLengthExpression( `computeStrokePatternLength(${sampleSizeExpression}, ${spacingExpression}, v_width)` ); } if ("stroke-width" in style) { builder.setStrokeWidthExpression( expressionToGlsl(context, style["stroke-width"], NumberType) ); } if ("stroke-offset" in style) { builder.setStrokeOffsetExpression( expressionToGlsl(context, style["stroke-offset"], NumberType) ); } if ("stroke-line-cap" in style) { builder.setStrokeCapExpression( expressionToGlsl(context, style["stroke-line-cap"], StringType) ); } if ("stroke-line-join" in style) { builder.setStrokeJoinExpression( expressionToGlsl(context, style["stroke-line-join"], StringType) ); } if ("stroke-miter-limit" in style) { builder.setStrokeMiterLimitExpression( expressionToGlsl(context, style["stroke-miter-limit"], NumberType) ); } if ("stroke-line-dash" in style) { context.functions["getSingleDashDistance"] = `float getSingleDashDistance(float distance, float radius, float dashOffset, float dashLength, float dashLengthTotal, float capType, float lineWidth) { float localDistance = mod(distance, dashLengthTotal); float distanceSegment = abs(localDistance - dashOffset - dashLength * 0.5) - dashLength * 0.5; distanceSegment = min(distanceSegment, dashLengthTotal - localDistance); if (capType == ${stringToGlsl("square")}) { distanceSegment -= lineWidth * 0.5; } else if (capType == ${stringToGlsl("round")}) { distanceSegment = min(distanceSegment, sqrt(distanceSegment * distanceSegment + radius * radius) - lineWidth * 0.5); } return distanceSegment; }`; let dashPattern = style["stroke-line-dash"].map( (v) => expressionToGlsl(context, v, NumberType) ); if (dashPattern.length % 2 === 1) { dashPattern = [...dashPattern, ...dashPattern]; } let offsetExpression = "0."; if ("stroke-line-dash-offset" in style) { offsetExpression = expressionToGlsl( context, style["stroke-line-dash-offset"], NumberType ); } const uniqueDashKey = computeHash(style["stroke-line-dash"]); const dashFunctionName = `dashDistanceField_${uniqueDashKey}`; const dashLengthsParamsDef = dashPattern.map((v, i) => `float dashLength${i}`).join(", "); const totalLengthDef = dashPattern.map((v, i) => `dashLength${i}`).join(" + "); let currentDashOffset = "0."; let distanceExpression = `getSingleDashDistance(distance, radius, ${currentDashOffset}, dashLength0, totalDashLength, capType, lineWidth)`; for (let i = 2; i < dashPattern.length; i += 2) { currentDashOffset = `${currentDashOffset} + dashLength${i - 2} + dashLength${i - 1}`; distanceExpression = `min(${distanceExpression}, getSingleDashDistance(distance, radius, ${currentDashOffset}, dashLength${i}, totalDashLength, capType, lineWidth))`; } context.functions[dashFunctionName] = `float ${dashFunctionName}(float distance, float radius, float capType, float lineWidth, ${dashLengthsParamsDef}) { float totalDashLength = ${totalLengthDef}; return ${distanceExpression}; }`; const dashLengthsCalls = dashPattern.map((v, i) => `${v}`).join(", "); builder.setStrokeDistanceFieldExpression( `${dashFunctionName}(currentLengthPx + ${offsetExpression}, currentRadiusPx, capType, v_width, ${dashLengthsCalls})` ); let patternLength = dashPattern.join(" + "); if (builder.getStrokePatternLengthExpression()) { context.functions["combinePatternLengths"] = `float combinePatternLengths(float patternLength1, float patternLength2) { return patternLength1 * patternLength2; }`; patternLength = `combinePatternLengths(${builder.getStrokePatternLengthExpression()}, ${patternLength})`; } builder.setStrokePatternLengthExpression(patternLength); } } function parseFillProperties(style, builder, uniforms, context) { if ("fill-color" in style) { builder.setFillColorExpression( expressionToGlsl(context, style["fill-color"], ColorType) ); } if ("fill-pattern-src" in style) { const textureId = computeHash(style["fill-pattern-src"]); const sizeExpression = parseImageProperties( style, builder, uniforms, "fill-pattern-", textureId ); let sampleSizeExpression = sizeExpression; let offsetExpression = "vec2(0.)"; if ("fill-pattern-offset" in style && "fill-pattern-size" in style) { sampleSizeExpression = expressionToGlsl( context, style[`fill-pattern-size`], NumberArrayType ); offsetExpression = parseImageOffsetProperties( style, "fill-pattern-", context, sizeExpression, sampleSizeExpression ); } context.functions["sampleFillPattern"] = `vec4 sampleFillPattern(sampler2D texture, vec2 textureSize, vec2 textureOffset, vec2 sampleSize, vec2 pxOrigin, vec2 pxPosition) { float scaleRatio = pow(2., mod(u_zoom + 0.5, 1.) - 0.5); vec2 pxRelativePos = pxPosition - pxOrigin; // rotate the relative position from origin by the current view rotation pxRelativePos = vec2(pxRelativePos.x * cos(u_rotation) - pxRelativePos.y * sin(u_rotation), pxRelativePos.x * sin(u_rotation) + pxRelativePos.y * cos(u_rotation)); // sample position is computed according to the sample offset & size vec2 samplePos = mod(pxRelativePos / scaleRatio, sampleSize); // also make sure that we're not sampling too close to the borders to avoid interpolation with outside pixels samplePos = clamp(samplePos, vec2(0.5), sampleSize - vec2(0.5)); samplePos.y = sampleSize.y - samplePos.y; // invert y axis so that images appear upright return texture2D(texture, (samplePos + textureOffset) / textureSize); }`; const textureName = `u_texture${textureId}`; let tintExpression = "1."; if ("fill-color" in style) { tintExpression = builder.getFillColorExpression(); } builder.setFillColorExpression( `${tintExpression} * sampleFillPattern(${textureName}, ${sizeExpression}, ${offsetExpression}, ${sampleSizeExpression}, pxOrigin, pxPos)` ); } } function parseLiteralStyle(style, variables, filter) { const context = newCompilationContext(); const builder = new ShaderBuilder(); const uniforms = {}; if ("icon-src" in style) { parseIconProperties(style, builder, uniforms, context); } else if ("shape-points" in style) { parseShapeProperties(style, builder, uniforms, context); } else if ("circle-radius" in style) { parseCircleProperties(style, builder, uniforms, context); } parseStrokeProperties(style, builder, uniforms, context); parseFillProperties(style, builder, uniforms, context); if (filter) { const parsedFilter = expressionToGlsl(context, filter, BooleanType); builder.setFragmentDiscardExpression(`!${parsedFilter}`); } const attributes = {}; function defineSpecialInput(contextPropName, glslPropName, type, callback) { if (!context[contextPropName]) { return; } const glslType = getGlslTypeFromType(type); const attrSize = getGlslSizeFromType(type); builder.addAttribute(`a_${glslPropName}`, glslType); attributes[glslPropName] = { size: attrSize, callback }; } defineSpecialInput( "geometryType", GEOMETRY_TYPE_PROPERTY_NAME, StringType, (feature) => getStringNumberEquivalent(computeGeometryType(feature.getGeometry())) ); defineSpecialInput( "featureId", FEATURE_ID_PROPERTY_NAME, StringType | NumberType, (feature) => { const id = feature.getId() ?? null; return typeof id === "string" ? getStringNumberEquivalent(id) : id; } ); applyContextToBuilder(builder, context); return { builder, attributes: { ...attributes, ...generateAttributesFromContext(context) }, uniforms: { ...uniforms, ...generateUniformsFromContext(context, variables) } }; } // node_modules/ol/render/webgl/VectorStyleRenderer.js var tmpColor = []; var WEBGL_WORKER; function getWebGLWorker() { if (!WEBGL_WORKER) { WEBGL_WORKER = create3(); } return WEBGL_WORKER; } var workerMessageCounter = 0; var Attributes2 = { POSITION: "a_position", LOCAL_POSITION: "a_localPosition", SEGMENT_START: "a_segmentStart", SEGMENT_END: "a_segmentEnd", MEASURE_START: "a_measureStart", MEASURE_END: "a_measureEnd", ANGLE_TANGENT_SUM: "a_angleTangentSum", JOIN_ANGLES: "a_joinAngles", DISTANCE_LOW: "a_distanceLow", DISTANCE_HIGH: "a_distanceHigh" }; var VectorStyleRenderer = class { /** * @param {FlatStyleLike|StyleShaders|Array} styles Vector styles expressed as flat styles, flat style rules or style shaders * @param {import('../../style/flat.js').StyleVariables} variables Style variables * @param {import('../../webgl/Helper.js').default} helper Helper * @param {boolean} [enableHitDetection] Whether to enable the hit detection (needs compatible shader) */ constructor(styles, variables, helper, enableHitDetection) { this.helper_; this.hitDetectionEnabled_ = !!enableHitDetection; this.styleShaders = convertStyleToShaders(styles, variables); this.customAttributes_ = {}; this.uniforms_ = {}; if (this.hitDetectionEnabled_) { this.customAttributes_["hitColor"] = { callback() { return colorEncodeIdAndPack(this.ref, tmpColor); }, size: 2 }; } for (const styleShader of this.styleShaders) { for (const attributeName in styleShader.attributes) { if (attributeName in this.customAttributes_) { continue; } this.customAttributes_[attributeName] = styleShader.attributes[attributeName]; } for (const uniformName in styleShader.uniforms) { if (uniformName in this.uniforms_) { continue; } this.uniforms_[uniformName] = styleShader.uniforms[uniformName]; } } this.renderPasses_ = this.styleShaders.map((styleShader) => { const renderPass = {}; const customAttributesDesc = Object.entries(this.customAttributes_).map( ([name, value]) => { const isUsed = name in styleShader.attributes || name === "hitColor"; return { name: isUsed ? `a_${name}` : null, // giving a null name means this is only used for "spacing" in between attributes size: value.size || 1, type: AttributeType.FLOAT }; } ); if (styleShader.builder.getFillVertexShader()) { renderPass.fillRenderPass = { vertexShader: styleShader.builder.getFillVertexShader(), fragmentShader: styleShader.builder.getFillFragmentShader(), attributesDesc: [ { name: Attributes2.POSITION, size: 2, type: AttributeType.FLOAT }, ...customAttributesDesc ], instancedAttributesDesc: [], // no instanced rendering for polygons instancePrimitiveVertexCount: 3 }; } if (styleShader.builder.getStrokeVertexShader()) { renderPass.strokeRenderPass = { vertexShader: styleShader.builder.getStrokeVertexShader(), fragmentShader: styleShader.builder.getStrokeFragmentShader(), attributesDesc: [ { name: Attributes2.LOCAL_POSITION, size: 2, type: AttributeType.FLOAT } ], instancedAttributesDesc: [ { name: Attributes2.SEGMENT_START, size: 2, type: AttributeType.FLOAT }, { name: Attributes2.MEASURE_START, size: 1, type: AttributeType.FLOAT }, { name: Attributes2.SEGMENT_END, size: 2, type: AttributeType.FLOAT }, { name: Attributes2.MEASURE_END, size: 1, type: AttributeType.FLOAT }, { name: Attributes2.JOIN_ANGLES, size: 2, type: AttributeType.FLOAT }, { name: Attributes2.DISTANCE_LOW, size: 1, type: AttributeType.FLOAT }, { name: Attributes2.DISTANCE_HIGH, size: 1, type: AttributeType.FLOAT }, { name: Attributes2.ANGLE_TANGENT_SUM, size: 1, type: AttributeType.FLOAT }, ...customAttributesDesc ], instancePrimitiveVertexCount: 6 }; } if (styleShader.builder.getSymbolVertexShader()) { renderPass.symbolRenderPass = { vertexShader: styleShader.builder.getSymbolVertexShader(), fragmentShader: styleShader.builder.getSymbolFragmentShader(), attributesDesc: [ { name: Attributes2.LOCAL_POSITION, size: 2, type: AttributeType.FLOAT } ], instancedAttributesDesc: [ { name: Attributes2.POSITION, size: 2, type: AttributeType.FLOAT }, ...customAttributesDesc ], instancePrimitiveVertexCount: 6 }; } return renderPass; }); this.hasFill_ = this.renderPasses_.some((pass) => pass.fillRenderPass); this.hasStroke_ = this.renderPasses_.some((pass) => pass.strokeRenderPass); this.hasSymbol_ = this.renderPasses_.some((pass) => pass.symbolRenderPass); this.setHelper(helper); } /** * @param {import('./MixedGeometryBatch.js').default} geometryBatch Geometry batch * @param {import("../../transform.js").Transform} transform Transform to apply to coordinates * @return {Promise} A promise resolving to WebGL buffers; returns null if buffers are empty */ async generateBuffers(geometryBatch, transform) { if (geometryBatch.isEmpty()) { return null; } const renderInstructions = this.generateRenderInstructions_( geometryBatch, transform ); const [polygonBuffers, lineStringBuffers, pointBuffers] = await Promise.all( [ this.generateBuffersForType_( renderInstructions.polygonInstructions, "Polygon", transform ), this.generateBuffersForType_( renderInstructions.lineStringInstructions, "LineString", transform ), this.generateBuffersForType_( renderInstructions.pointInstructions, "Point", transform ) ] ); const invertVerticesTransform = makeInverse( create(), transform ); return { polygonBuffers, lineStringBuffers, pointBuffers, invertVerticesTransform }; } /** * @param {import('./MixedGeometryBatch.js').default} geometryBatch Geometry batch * @param {import("../../transform.js").Transform} transform Transform to apply to coordinates * @return {RenderInstructions} Render instructions * @private */ generateRenderInstructions_(geometryBatch, transform) { const polygonInstructions = this.hasFill_ ? generatePolygonRenderInstructions( geometryBatch.polygonBatch, new Float32Array(0), this.customAttributes_, transform ) : null; const lineStringInstructions = this.hasStroke_ ? generateLineStringRenderInstructions( geometryBatch.lineStringBatch, new Float32Array(0), this.customAttributes_, transform ) : null; const pointInstructions = this.hasSymbol_ ? generatePointRenderInstructions( geometryBatch.pointBatch, new Float32Array(0), this.customAttributes_, transform ) : null; return { polygonInstructions, lineStringInstructions, pointInstructions }; } /** * @param {Float32Array|null} renderInstructions Render instructions * @param {import("../../geom/Geometry.js").Type} geometryType Geometry type * @param {import("../../transform.js").Transform} transform Transform to apply to coordinates * @return {Promise|null} Indices buffer and vertices buffer; null if nothing to render * @private */ generateBuffersForType_(renderInstructions, geometryType, transform) { if (renderInstructions === null) { return null; } const messageId = workerMessageCounter++; let messageType; switch (geometryType) { case "Polygon": messageType = WebGLWorkerMessageType.GENERATE_POLYGON_BUFFERS; break; case "LineString": messageType = WebGLWorkerMessageType.GENERATE_LINE_STRING_BUFFERS; break; case "Point": messageType = WebGLWorkerMessageType.GENERATE_POINT_BUFFERS; break; default: } const message = { id: messageId, type: messageType, renderInstructions: renderInstructions.buffer, renderInstructionsTransform: transform, customAttributesSize: getCustomAttributesSize(this.customAttributes_) }; const WEBGL_WORKER2 = getWebGLWorker(); WEBGL_WORKER2.postMessage(message, [renderInstructions.buffer]); renderInstructions = null; return new Promise((resolve) => { const handleMessage = (event) => { const received = event.data; if (received.id !== messageId) { return; } WEBGL_WORKER2.removeEventListener("message", handleMessage); if (!this.helper_.getGL()) { return; } const indicesBuffer = new Buffer_default( ELEMENT_ARRAY_BUFFER, DYNAMIC_DRAW ).fromArrayBuffer(received.indicesBuffer); const vertexAttributesBuffer = new Buffer_default( ARRAY_BUFFER, DYNAMIC_DRAW ).fromArrayBuffer(received.vertexAttributesBuffer); const instanceAttributesBuffer = new Buffer_default( ARRAY_BUFFER, DYNAMIC_DRAW ).fromArrayBuffer(received.instanceAttributesBuffer); this.helper_.flushBufferData(indicesBuffer); this.helper_.flushBufferData(vertexAttributesBuffer); this.helper_.flushBufferData(instanceAttributesBuffer); resolve([ indicesBuffer, vertexAttributesBuffer, instanceAttributesBuffer ]); }; WEBGL_WORKER2.addEventListener("message", handleMessage); }); } /** * Render the geometries in the given buffers. * @param {WebGLBuffers} buffers WebGL Buffers to draw * @param {import("../../Map.js").FrameState} frameState Frame state * @param {function(): void} preRenderCallback This callback will be called right before drawing, and can be used to set uniforms */ render(buffers, frameState, preRenderCallback) { for (const renderPass of this.renderPasses_) { renderPass.fillRenderPass && this.renderInternal_( buffers.polygonBuffers[0], buffers.polygonBuffers[1], buffers.polygonBuffers[2], renderPass.fillRenderPass, frameState, preRenderCallback ); renderPass.strokeRenderPass && this.renderInternal_( buffers.lineStringBuffers[0], buffers.lineStringBuffers[1], buffers.lineStringBuffers[2], renderPass.strokeRenderPass, frameState, preRenderCallback ); renderPass.symbolRenderPass && this.renderInternal_( buffers.pointBuffers[0], buffers.pointBuffers[1], buffers.pointBuffers[2], renderPass.symbolRenderPass, frameState, preRenderCallback ); } } /** * @param {WebGLArrayBuffer} indicesBuffer Indices buffer * @param {WebGLArrayBuffer} vertexAttributesBuffer Vertex attributes buffer * @param {WebGLArrayBuffer} instanceAttributesBuffer Instance attributes buffer * @param {SubRenderPass} subRenderPass Render pass (program, attributes, etc.) specific to one geometry type * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {function(): void} preRenderCallback This callback will be called right before drawing, and can be used to set uniforms * @private */ renderInternal_(indicesBuffer, vertexAttributesBuffer, instanceAttributesBuffer, subRenderPass, frameState, preRenderCallback) { const renderCount = indicesBuffer.getSize(); if (renderCount === 0) { return; } const usesInstancedRendering = subRenderPass.instancedAttributesDesc.length; this.helper_.useProgram(subRenderPass.program, frameState); this.helper_.bindBuffer(vertexAttributesBuffer); this.helper_.bindBuffer(indicesBuffer); this.helper_.enableAttributes(subRenderPass.attributesDesc); this.helper_.bindBuffer(instanceAttributesBuffer); this.helper_.enableAttributesInstanced( subRenderPass.instancedAttributesDesc ); preRenderCallback(); if (usesInstancedRendering) { const instanceAttributesStride = subRenderPass.instancedAttributesDesc.reduce( (prev, curr) => prev + (curr.size || 1), 0 ); const instanceCount = instanceAttributesBuffer.getSize() / instanceAttributesStride; this.helper_.drawElementsInstanced(0, renderCount, instanceCount); } else { this.helper_.drawElements(0, renderCount); } } /** * @param {import('../../webgl/Helper.js').default} helper Helper * @param {WebGLBuffers} buffers WebGL Buffers to reload if any */ setHelper(helper, buffers = null) { this.helper_ = helper; for (const renderPass of this.renderPasses_) { if (renderPass.fillRenderPass) { renderPass.fillRenderPass.program = this.helper_.getProgram( renderPass.fillRenderPass.fragmentShader, renderPass.fillRenderPass.vertexShader ); } if (renderPass.strokeRenderPass) { renderPass.strokeRenderPass.program = this.helper_.getProgram( renderPass.strokeRenderPass.fragmentShader, renderPass.strokeRenderPass.vertexShader ); } if (renderPass.symbolRenderPass) { renderPass.symbolRenderPass.program = this.helper_.getProgram( renderPass.symbolRenderPass.fragmentShader, renderPass.symbolRenderPass.vertexShader ); } } this.helper_.addUniforms(this.uniforms_); if (buffers) { if (buffers.polygonBuffers) { this.helper_.flushBufferData(buffers.polygonBuffers[0]); this.helper_.flushBufferData(buffers.polygonBuffers[1]); this.helper_.flushBufferData(buffers.polygonBuffers[2]); } if (buffers.lineStringBuffers) { this.helper_.flushBufferData(buffers.lineStringBuffers[0]); this.helper_.flushBufferData(buffers.lineStringBuffers[1]); this.helper_.flushBufferData(buffers.lineStringBuffers[2]); } if (buffers.pointBuffers) { this.helper_.flushBufferData(buffers.pointBuffers[0]); this.helper_.flushBufferData(buffers.pointBuffers[1]); this.helper_.flushBufferData(buffers.pointBuffers[2]); } } } }; var VectorStyleRenderer_default = VectorStyleRenderer; function convertStyleToShaders(style, variables) { const asArray2 = Array.isArray(style) ? style : [style]; if ("style" in asArray2[0]) { const shaders = []; const rules = ( /** @type {Array} */ asArray2 ); const previousFilters = []; for (const rule of rules) { const ruleStyles = Array.isArray(rule.style) ? rule.style : [rule.style]; let currentFilter = rule.filter; if (rule.else && previousFilters.length) { currentFilter = [ "all", ...previousFilters.map((filter) => ["!", filter]) ]; if (rule.filter) { currentFilter.push(rule.filter); } if (currentFilter.length < 3) { currentFilter = currentFilter[1]; } } if (rule.filter) { previousFilters.push(rule.filter); } const styleShaders = ruleStyles.map( (style2) => parseLiteralStyle(style2, variables, currentFilter) ); shaders.push(...styleShaders); } return shaders; } if ("builder" in asArray2[0]) { return ( /** @type {Array} */ asArray2 ); } return ( /** @type {Array} */ asArray2.map( (style2) => parseLiteralStyle(style2, variables, null) ) ); } // node_modules/ol/webgl/RenderTarget.js var tmpArray4 = new Uint8Array(4); var WebGLRenderTarget = class { /** * @param {import("./Helper.js").default} helper WebGL helper; mandatory. * @param {Array} [size] Expected size of the render target texture; note: this can be changed later on. */ constructor(helper, size) { this.helper_ = helper; const gl = helper.getGL(); this.texture_ = gl.createTexture(); this.framebuffer_ = gl.createFramebuffer(); this.depthbuffer_ = gl.createRenderbuffer(); this.size_ = size || [1, 1]; this.data_ = new Uint8Array(0); this.dataCacheDirty_ = true; this.updateSize_(); } /** * Changes the size of the render target texture. Note: will do nothing if the size * is already the same. * @param {Array} size Expected size of the render target texture */ setSize(size) { if (equals(size, this.size_)) { return; } this.size_[0] = size[0]; this.size_[1] = size[1]; this.updateSize_(); } /** * Returns the size of the render target texture * @return {Array} Size of the render target texture */ getSize() { return this.size_; } /** * This will cause following calls to `#readAll` or `#readPixel` to download the content of the * render target into memory, which is an expensive operation. * This content will be kept in cache but should be cleared after each new render. */ clearCachedData() { this.dataCacheDirty_ = true; } /** * Returns the full content of the frame buffer as a series of r, g, b, a components * in the 0-255 range (unsigned byte). * @return {Uint8Array} Integer array of color values */ readAll() { if (this.dataCacheDirty_) { const size = this.size_; const gl = this.helper_.getGL(); gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer_); gl.readPixels( 0, 0, size[0], size[1], gl.RGBA, gl.UNSIGNED_BYTE, this.data_ ); this.dataCacheDirty_ = false; } return this.data_; } /** * Reads one pixel of the frame buffer as an array of r, g, b, a components * in the 0-255 range (unsigned byte). * If x and/or y are outside of existing data, an array filled with 0 is returned. * @param {number} x Pixel coordinate * @param {number} y Pixel coordinate * @return {Uint8Array} Integer array with one color value (4 components) */ readPixel(x, y) { if (x < 0 || y < 0 || x > this.size_[0] || y >= this.size_[1]) { tmpArray4[0] = 0; tmpArray4[1] = 0; tmpArray4[2] = 0; tmpArray4[3] = 0; return tmpArray4; } this.readAll(); const index = Math.floor(x) + (this.size_[1] - Math.floor(y) - 1) * this.size_[0]; tmpArray4[0] = this.data_[index * 4]; tmpArray4[1] = this.data_[index * 4 + 1]; tmpArray4[2] = this.data_[index * 4 + 2]; tmpArray4[3] = this.data_[index * 4 + 3]; return tmpArray4; } /** * @return {WebGLTexture} Texture to render to */ getTexture() { return this.texture_; } /** * @return {WebGLFramebuffer} Frame buffer of the render target */ getFramebuffer() { return this.framebuffer_; } /** * @return {WebGLRenderbuffer} Depth buffer of the render target */ getDepthbuffer() { return this.depthbuffer_; } /** * @private */ updateSize_() { const size = this.size_; const gl = this.helper_.getGL(); this.texture_ = this.helper_.createTexture(size, null, this.texture_); gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer_); gl.viewport(0, 0, size[0], size[1]); gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture_, 0 ); gl.bindRenderbuffer(gl.RENDERBUFFER, this.depthbuffer_); gl.renderbufferStorage( gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size[0], size[1] ); gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.depthbuffer_ ); this.data_ = new Uint8Array(size[0] * size[1] * 4); } }; var RenderTarget_default = WebGLRenderTarget; // node_modules/ol/renderer/webgl/worldUtil.js function getWorldParameters(frameState, layer) { const projection = frameState.viewState.projection; const vectorSource = layer.getSource(); const multiWorld = vectorSource.getWrapX() && projection.canWrapX(); const projectionExtent = projection.getExtent(); const extent = frameState.extent; const worldWidth = multiWorld ? getWidth(projectionExtent) : null; const endWorld = multiWorld ? Math.ceil((extent[2] - projectionExtent[2]) / worldWidth) + 1 : 1; const startWorld = multiWorld ? Math.floor((extent[0] - projectionExtent[0]) / worldWidth) : 0; return [startWorld, endWorld, worldWidth]; } // node_modules/ol/renderer/webgl/VectorLayer.js var Uniforms3 = { ...DefaultUniform, RENDER_EXTENT: "u_renderExtent", // intersection of layer, source, and view extent PATTERN_ORIGIN: "u_patternOrigin", GLOBAL_ALPHA: "u_globalAlpha" }; var WebGLVectorLayerRenderer = class extends Layer_default2 { /** * @param {import("../../layer/Layer.js").default} layer Layer. * @param {Options} options Options. */ constructor(layer, options) { const uniforms = { [Uniforms3.RENDER_EXTENT]: [0, 0, 0, 0], [Uniforms3.PATTERN_ORIGIN]: [0, 0], [Uniforms3.GLOBAL_ALPHA]: 1 }; super(layer, { uniforms, postProcesses: options.postProcesses }); this.hitDetectionEnabled_ = !options.disableHitDetection; this.hitRenderTarget_; this.sourceRevision_ = -1; this.previousExtent_ = createEmpty(); this.currentTransform_ = create(); this.tmpCoords_ = [0, 0]; this.tmpTransform_ = create(); this.tmpMat4_ = create2(); this.currentFrameStateTransform_ = create(); this.styleVariables_ = {}; this.style_ = []; this.styleRenderer_ = null; this.buffers_ = null; this.applyOptions_(options); this.batch_ = new MixedGeometryBatch_default(); this.initialFeaturesAdded_ = false; this.sourceListenKeys_ = null; } /** * @private * @param {import("../../Map.js").FrameState} frameState Frame state. */ addInitialFeatures_(frameState) { const source = this.getLayer().getSource(); const userProjection = getUserProjection(); let projectionTransform; if (userProjection) { projectionTransform = getTransformFromProjections( userProjection, frameState.viewState.projection ); } this.batch_.addFeatures(source.getFeatures(), projectionTransform); this.sourceListenKeys_ = [ listen( source, VectorEventType_default.ADDFEATURE, this.handleSourceFeatureAdded_.bind(this, projectionTransform) ), listen( source, VectorEventType_default.CHANGEFEATURE, this.handleSourceFeatureChanged_.bind(this, projectionTransform), this ), listen( source, VectorEventType_default.REMOVEFEATURE, this.handleSourceFeatureDelete_, this ), listen( source, VectorEventType_default.CLEAR, this.handleSourceFeatureClear_, this ) ]; } /** * @param {Options} options Options. * @private */ applyOptions_(options) { this.styleVariables_ = options.variables; this.style_ = options.style; } /** * @private */ createRenderers_() { this.buffers_ = null; this.styleRenderer_ = new VectorStyleRenderer_default( this.style_, this.styleVariables_, this.helper, this.hitDetectionEnabled_ ); } /** * @override */ reset(options) { this.applyOptions_(options); if (this.helper) { this.createRenderers_(); } super.reset(options); } /** * @override */ afterHelperCreated() { if (this.styleRenderer_) { this.styleRenderer_.setHelper(this.helper, this.buffers_); } else { this.createRenderers_(); } if (this.hitDetectionEnabled_) { this.hitRenderTarget_ = new RenderTarget_default(this.helper); } } /** * @param {import("../../proj.js").TransformFunction} projectionTransform Transform function. * @param {import("../../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceFeatureAdded_(projectionTransform, event) { const feature = event.feature; this.batch_.addFeature(feature, projectionTransform); } /** * @param {import("../../proj.js").TransformFunction} projectionTransform Transform function. * @param {import("../../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceFeatureChanged_(projectionTransform, event) { const feature = event.feature; this.batch_.changeFeature(feature, projectionTransform); } /** * @param {import("../../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceFeatureDelete_(event) { const feature = event.feature; this.batch_.removeFeature(feature); } /** * @private */ handleSourceFeatureClear_() { this.batch_.clear(); } /** * @param {import("../../transform.js").Transform} batchInvertTransform Inverse of the transformation in which geometries are expressed * @private */ applyUniforms_(batchInvertTransform) { setFromArray(this.tmpTransform_, this.currentFrameStateTransform_); multiply(this.tmpTransform_, batchInvertTransform); this.helper.setUniformMatrixValue( Uniforms3.PROJECTION_MATRIX, fromTransform(this.tmpMat4_, this.tmpTransform_) ); makeInverse(this.tmpTransform_, this.tmpTransform_); this.helper.setUniformMatrixValue( Uniforms3.SCREEN_TO_WORLD_MATRIX, fromTransform(this.tmpMat4_, this.tmpTransform_) ); this.tmpCoords_[0] = 0; this.tmpCoords_[1] = 0; makeInverse(this.tmpTransform_, batchInvertTransform); apply(this.tmpTransform_, this.tmpCoords_); this.helper.setUniformFloatVec2(Uniforms3.PATTERN_ORIGIN, this.tmpCoords_); } /** * Render the layer. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {HTMLElement} The rendered element. * @override */ renderFrame(frameState) { const gl = this.helper.getGL(); this.preRender(gl, frameState); const [startWorld, endWorld, worldWidth] = getWorldParameters( frameState, this.getLayer() ); this.helper.prepareDraw(frameState); this.renderWorlds(frameState, false, startWorld, endWorld, worldWidth); this.helper.finalizeDraw( frameState, this.dispatchPreComposeEvent, this.dispatchPostComposeEvent ); const canvas = this.helper.getCanvas(); if (this.hitDetectionEnabled_) { this.renderWorlds(frameState, true, startWorld, endWorld, worldWidth); this.hitRenderTarget_.clearCachedData(); } this.postRender(gl, frameState); return canvas; } /** * Determine whether renderFrame should be called. * @param {import("../../Map.js").FrameState} frameState Frame state. * @return {boolean} Layer is ready to be rendered. * @override */ prepareFrameInternal(frameState) { if (!this.initialFeaturesAdded_) { this.addInitialFeatures_(frameState); this.initialFeaturesAdded_ = true; } const layer = this.getLayer(); const vectorSource = layer.getSource(); const viewState = frameState.viewState; const viewNotMoving = !frameState.viewHints[ViewHint_default.ANIMATING] && !frameState.viewHints[ViewHint_default.INTERACTING]; const extentChanged = !equals2(this.previousExtent_, frameState.extent); const sourceChanged = this.sourceRevision_ < vectorSource.getRevision(); if (sourceChanged) { this.sourceRevision_ = vectorSource.getRevision(); } if (viewNotMoving && (extentChanged || sourceChanged)) { const projection = viewState.projection; const resolution = viewState.resolution; const renderBuffer = layer instanceof BaseVector_default ? layer.getRenderBuffer() : 0; const extent = buffer(frameState.extent, renderBuffer * resolution); const userProjection = getUserProjection(); if (userProjection) { vectorSource.loadFeatures( toUserExtent(extent, userProjection), toUserResolution(resolution, projection), userProjection ); } else { vectorSource.loadFeatures(extent, resolution, projection); } this.ready = false; const transform = this.helper.makeProjectionTransform( frameState, create() ); this.styleRenderer_.generateBuffers(this.batch_, transform).then((buffers) => { if (this.buffers_) { this.disposeBuffers(this.buffers_); } this.buffers_ = buffers; this.ready = true; this.getLayer().changed(); }); this.previousExtent_ = frameState.extent.slice(); } return true; } /** * Render the world, either to the main framebuffer or to the hit framebuffer * @param {import("../../Map.js").FrameState} frameState current frame state * @param {boolean} forHitDetection whether the rendering is for hit detection * @param {number} startWorld the world to render in the first iteration * @param {number} endWorld the last world to render * @param {number} worldWidth the width of the worlds being rendered */ renderWorlds(frameState, forHitDetection, startWorld, endWorld, worldWidth) { let world = startWorld; if (forHitDetection) { this.hitRenderTarget_.setSize([ Math.floor(frameState.size[0] / 2), Math.floor(frameState.size[1] / 2) ]); this.helper.prepareDrawToRenderTarget( frameState, this.hitRenderTarget_, true ); } do { this.helper.makeProjectionTransform( frameState, this.currentFrameStateTransform_ ); translate( this.currentFrameStateTransform_, world * worldWidth, 0 ); if (!this.buffers_) { continue; } this.styleRenderer_.render(this.buffers_, frameState, () => { this.applyUniforms_(this.buffers_.invertVerticesTransform); this.helper.applyHitDetectionUniform(forHitDetection); }); } while (++world < endWorld); } /** * @param {import("../../coordinate.js").Coordinate} coordinate Coordinate. * @param {import("../../Map.js").FrameState} frameState Frame state. * @param {number} hitTolerance Hit tolerance in pixels. * @param {import("../vector.js").FeatureCallback} callback Feature callback. * @param {Array>} matches The hit detected matches with tolerance. * @return {T|undefined} Callback result. * @template T * @override */ forEachFeatureAtCoordinate(coordinate, frameState, hitTolerance, callback, matches) { assert( this.hitDetectionEnabled_, "`forEachFeatureAtCoordinate` cannot be used on a WebGL layer if the hit detection logic has been disabled using the `disableHitDetection: true` option." ); if (!this.styleRenderer_ || !this.hitDetectionEnabled_) { return void 0; } const pixel = apply( frameState.coordinateToPixelTransform, coordinate.slice() ); const data = this.hitRenderTarget_.readPixel(pixel[0] / 2, pixel[1] / 2); const color = [data[0] / 255, data[1] / 255, data[2] / 255, data[3] / 255]; const ref = colorDecodeId(color); const feature = this.batch_.getFeatureFromRef(ref); if (feature) { return callback(feature, this.getLayer(), null); } return void 0; } /** * Will release a set of Webgl buffers * @param {import('../../render/webgl/VectorStyleRenderer.js').WebGLBuffers} buffers Buffers */ disposeBuffers(buffers) { const disposeBuffersOfType = (typeBuffers) => { for (const buffer2 of typeBuffers) { if (buffer2) { this.helper.deleteBuffer(buffer2); } } }; if (buffers.pointBuffers) { disposeBuffersOfType(buffers.pointBuffers); } if (buffers.lineStringBuffers) { disposeBuffersOfType(buffers.lineStringBuffers); } if (buffers.polygonBuffers) { disposeBuffersOfType(buffers.polygonBuffers); } } /** * Clean up. * @override */ disposeInternal() { if (this.buffers_) { this.disposeBuffers(this.buffers_); } if (this.sourceListenKeys_) { this.sourceListenKeys_.forEach(function(key) { unlistenByKey(key); }); this.sourceListenKeys_ = null; } super.disposeInternal(); } renderDeclutter() { } }; var VectorLayer_default = WebGLVectorLayerRenderer; // node_modules/ol/layer/Heatmap.js var Property = { BLUR: "blur", GRADIENT: "gradient", RADIUS: "radius" }; var DEFAULT_GRADIENT = ["#00f", "#0ff", "#0f0", "#ff0", "#f00"]; var Heatmap = class extends BaseVector_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options ? options : {}; const baseOptions = Object.assign({}, options); delete baseOptions.gradient; delete baseOptions.radius; delete baseOptions.blur; delete baseOptions.weight; super(baseOptions); this.filter_ = options.filter ?? true; this.styleVariables_ = options.variables || {}; this.gradient_ = null; this.addChangeListener(Property.GRADIENT, this.handleGradientChanged_); this.setGradient(options.gradient ? options.gradient : DEFAULT_GRADIENT); this.setBlur(options.blur !== void 0 ? options.blur : 15); this.setRadius(options.radius !== void 0 ? options.radius : 8); const weight = options.weight ? options.weight : "weight"; this.weight_ = weight; this.setRenderOrder(null); } /** * Return the blur size in pixels. * @return {import("../style/flat.js").NumberExpression} Blur size in pixels. * @api * @observable */ getBlur() { return ( /** @type {import("../style/flat.js").NumberExpression} */ this.get(Property.BLUR) ); } /** * Return the gradient colors as array of strings. * @return {Array} Colors. * @api * @observable */ getGradient() { return ( /** @type {Array} */ this.get(Property.GRADIENT) ); } /** * Return the size of the radius in pixels. * @return {import("../style/flat.js").NumberExpression} Radius size in pixel. * @api * @observable */ getRadius() { return ( /** @type {import("../style/flat.js").NumberExpression} */ this.get(Property.RADIUS) ); } /** * @private */ handleGradientChanged_() { this.gradient_ = createGradient(this.getGradient()); } /** * Set the blur size in pixels. * @param {import("../style/flat.js").NumberExpression} blur Blur size in pixels (supports expressions). * @api * @observable */ setBlur(blur) { const previousValue = this.get(Property.BLUR); this.set(Property.BLUR, blur); if (typeof blur === "number" && typeof previousValue === "number") { this.changed(); return; } this.clearRenderer(); } /** * Set the gradient colors as array of strings. * @param {Array} colors Gradient. * @api * @observable */ setGradient(colors) { this.set(Property.GRADIENT, colors); } /** * Set the size of the radius in pixels. * @param {import("../style/flat.js").NumberExpression} radius Radius size in pixel (supports expressions). * @api * @observable */ setRadius(radius) { const previousValue = this.get(Property.RADIUS); this.set(Property.RADIUS, radius); if (typeof radius === "number" && typeof previousValue === "number") { this.changed(); return; } this.clearRenderer(); } /** * Set the filter expression * @param {import("../style/flat.js").BooleanExpression} filter Filter expression * @api */ setFilter(filter) { this.filter_ = filter; this.changed(); this.clearRenderer(); } /** * Set the weight expression * @param {WeightExpression} weight Weight expression * @api */ setWeight(weight) { this.weight_ = weight; this.changed(); this.clearRenderer(); } /** * @override */ createRenderer() { const builder = new ShaderBuilder(); const context = newCompilationContext(); const filterCompiled = expressionToGlsl(context, this.filter_, BooleanType); let radiusCompiled = expressionToGlsl( context, this.getRadius(), NumberType ); let blurCompiled = expressionToGlsl(context, this.getBlur(), NumberType); const blurRadiusUniforms = {}; if (typeof this.getBlur() === "number") { blurCompiled = "a_blur"; blurRadiusUniforms["a_blur"] = () => this.getBlur(); builder.addUniform("a_blur", "float"); } if (typeof this.getRadius() === "number") { radiusCompiled = "a_radius"; blurRadiusUniforms["a_radius"] = () => this.getRadius(); builder.addUniform("a_radius", "float"); } const weightAttribute = {}; let weightExpression = null; if (typeof this.weight_ === "string" || typeof this.weight_ === "function") { const weightFunction = typeof this.weight_ === "string" ? (feature) => feature.get(this.weight_) : this.weight_; weightAttribute["prop_weight"] = { size: 1, callback: (feature) => { const weightValue = weightFunction(feature); return weightValue !== void 0 ? clamp(weightValue, 0, 1) : 1; } }; weightExpression = "a_prop_weight"; builder.addAttribute("a_prop_weight", "float"); } else { const clampedWeight = ["clamp", this.weight_, 0, 1]; weightExpression = expressionToGlsl(context, clampedWeight, NumberType); } builder.addFragmentShaderFunction( `float getBlurSlope() { float blur = max(1., ${blurCompiled}); float radius = ${radiusCompiled}; return radius / blur; }` ).setSymbolSizeExpression(`vec2(${radiusCompiled} + ${blurCompiled}) * 2.`).setSymbolColorExpression( `vec4(smoothstep(0., 1., (1. - length(coordsPx * 2. / v_quadSizePx)) * getBlurSlope()) * ${weightExpression})` ).setStrokeColorExpression( `vec4(smoothstep(0., 1., (1. - length(currentRadiusPx * 2. / v_width)) * getBlurSlope()) * ${weightExpression})` ).setStrokeWidthExpression(`(${radiusCompiled} + ${blurCompiled}) * 2.`).setFillColorExpression(`vec4(${weightExpression})`).setFragmentDiscardExpression(`!${filterCompiled}`); applyContextToBuilder(builder, context); const attributes = generateAttributesFromContext(context); const uniforms = generateUniformsFromContext(context, this.styleVariables_); return new VectorLayer_default(this, { className: this.getClassName(), variables: this.styleVariables_, style: { builder, attributes: { ...attributes, ...weightAttribute }, uniforms: { ...uniforms, ...blurRadiusUniforms } }, disableHitDetection: false, postProcesses: [ { fragmentShader: ` precision mediump float; uniform sampler2D u_image; uniform sampler2D u_gradientTexture; uniform float u_opacity; varying vec2 v_texCoord; void main() { vec4 color = texture2D(u_image, v_texCoord); gl_FragColor.a = color.a * u_opacity; gl_FragColor.rgb = texture2D(u_gradientTexture, vec2(0.5, color.a)).rgb; gl_FragColor.rgb *= gl_FragColor.a; }`, uniforms: { u_gradientTexture: () => this.gradient_, u_opacity: () => this.getOpacity() } } ] }); } /** * Update any variables used by the layer style and trigger a re-render. * @param {import('../style/flat.js').StyleVariables} variables Variables to update. */ updateStyleVariables(variables) { Object.assign(this.styleVariables_, variables); this.changed(); } /** * @override */ renderDeclutter() { } }; function createGradient(colors) { const width = 1; const height = 256; const context = createCanvasContext2D(width, height); const gradient = context.createLinearGradient(0, 0, width, height); const step = 1 / (colors.length - 1); for (let i = 0, ii = colors.length; i < ii; ++i) { gradient.addColorStop(i * step, colors[i]); } context.fillStyle = gradient; context.fillRect(0, 0, width, height); return context.canvas; } var Heatmap_default = Heatmap; export { VectorTile_default, ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER, DYNAMIC_DRAW, Buffer_default, DefaultUniform, AttributeType, Layer_default2 as Layer_default, Uniforms2 as Uniforms, Attributes, TileLayer_default2 as TileLayer_default, getStringNumberEquivalent, uniformNameForVariable, newCompilationContext, PALETTE_TEXTURE_ARRAY, expressionToGlsl, create3 as create, WebGLWorkerMessageType, colorEncodeIdAndPack, colorDecodeId, parseLiteralStyle, RenderTarget_default, getWorldParameters, VectorLayer_default, Heatmap_default }; //# sourceMappingURL=chunk-YUMATXXX.js.map