UNPKG

@deck.gl/layers

Version:

deck.gl core layers

4 lines 405 kB
{ "version": 3, "sources": ["../src/index.ts", "../src/arc-layer/arc-layer.ts", "../src/arc-layer/arc-layer-uniforms.ts", "../src/arc-layer/arc-layer-vertex.glsl.ts", "../src/arc-layer/arc-layer-fragment.glsl.ts", "../src/bitmap-layer/bitmap-layer.ts", "../src/bitmap-layer/create-mesh.ts", "../src/bitmap-layer/bitmap-layer-uniforms.ts", "../src/bitmap-layer/bitmap-layer-vertex.ts", "../src/bitmap-layer/bitmap-layer-fragment.ts", "../src/icon-layer/icon-layer.ts", "../src/icon-layer/icon-layer-uniforms.ts", "../src/icon-layer/icon-layer-vertex.glsl.ts", "../src/icon-layer/icon-layer-fragment.glsl.ts", "../src/icon-layer/icon-manager.ts", "../src/line-layer/line-layer.ts", "../src/line-layer/line-layer-uniforms.ts", "../src/line-layer/line-layer.wgsl.ts", "../src/line-layer/line-layer-vertex.glsl.ts", "../src/line-layer/line-layer-fragment.glsl.ts", "../src/point-cloud-layer/point-cloud-layer.ts", "../src/point-cloud-layer/point-cloud-layer-uniforms.ts", "../src/point-cloud-layer/point-cloud-layer-vertex.glsl.ts", "../src/point-cloud-layer/point-cloud-layer-fragment.glsl.ts", "../src/scatterplot-layer/scatterplot-layer.ts", "../src/scatterplot-layer/scatterplot-layer-uniforms.ts", "../src/scatterplot-layer/scatterplot-layer-vertex.glsl.ts", "../src/scatterplot-layer/scatterplot-layer-fragment.glsl.ts", "../src/scatterplot-layer/scatterplot-layer.wgsl.ts", "../src/column-layer/column-layer.ts", "../src/column-layer/column-geometry.ts", "../src/column-layer/column-layer-uniforms.ts", "../src/column-layer/column-layer-vertex.glsl.ts", "../src/column-layer/column-layer-fragment.glsl.ts", "../src/column-layer/grid-cell-layer.ts", "../src/path-layer/path-layer.ts", "../src/path-layer/path-tesselator.ts", "../src/path-layer/path.ts", "../src/path-layer/path-layer-uniforms.ts", "../src/path-layer/path-layer-vertex.glsl.ts", "../src/path-layer/path-layer-fragment.glsl.ts", "../src/polygon-layer/polygon-layer.ts", "../src/solid-polygon-layer/solid-polygon-layer.ts", "../src/solid-polygon-layer/polygon.ts", "../src/solid-polygon-layer/polygon-tesselator.ts", "../src/solid-polygon-layer/solid-polygon-layer-uniforms.ts", "../src/solid-polygon-layer/solid-polygon-layer-vertex-main.glsl.ts", "../src/solid-polygon-layer/solid-polygon-layer-vertex-top.glsl.ts", "../src/solid-polygon-layer/solid-polygon-layer-vertex-side.glsl.ts", "../src/solid-polygon-layer/solid-polygon-layer-fragment.glsl.ts", "../src/utils.ts", "../src/geojson-layer/geojson-layer.ts", "../src/geojson-layer/geojson-binary.ts", "../src/text-layer/text-layer.ts", "../src/text-layer/multi-icon-layer/multi-icon-layer.ts", "../src/text-layer/multi-icon-layer/sdf-uniforms.ts", "../src/text-layer/multi-icon-layer/multi-icon-layer-fragment.glsl.ts", "../src/text-layer/font-atlas-manager.ts", "../src/text-layer/utils.ts", "../src/text-layer/lru-cache.ts", "../src/text-layer/text-background-layer/text-background-layer.ts", "../src/text-layer/text-background-layer/text-background-layer-uniforms.ts", "../src/text-layer/text-background-layer/text-background-layer-vertex.glsl.ts", "../src/text-layer/text-background-layer/text-background-layer-fragment.glsl.ts", "../src/geojson-layer/sub-layer-map.ts", "../src/geojson-layer/geojson.ts", "../src/geojson-layer/geojson-layer-props.ts"], "sourcesContent": ["// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n/* eslint-disable max-len */\n\n// Core Layers\nexport {default as ArcLayer} from './arc-layer/arc-layer';\nexport {default as BitmapLayer} from './bitmap-layer/bitmap-layer';\nexport {default as IconLayer} from './icon-layer/icon-layer';\nexport {default as LineLayer} from './line-layer/line-layer';\nexport {default as PointCloudLayer} from './point-cloud-layer/point-cloud-layer';\nexport {default as ScatterplotLayer} from './scatterplot-layer/scatterplot-layer';\nexport {default as ColumnLayer} from './column-layer/column-layer';\nexport {default as GridCellLayer} from './column-layer/grid-cell-layer';\nexport {default as PathLayer} from './path-layer/path-layer';\nexport {default as PolygonLayer} from './polygon-layer/polygon-layer';\nexport {default as GeoJsonLayer} from './geojson-layer/geojson-layer';\nexport {default as TextLayer} from './text-layer/text-layer';\nexport {default as SolidPolygonLayer} from './solid-polygon-layer/solid-polygon-layer';\n\n// Experimental layer exports\nexport {default as _MultiIconLayer} from './text-layer/multi-icon-layer/multi-icon-layer';\nexport {default as _TextBackgroundLayer} from './text-layer/text-background-layer/text-background-layer';\n\n// Types\nexport type {ArcLayerProps} from './arc-layer/arc-layer';\nexport type {\n BitmapLayerProps,\n BitmapBoundingBox,\n BitmapLayerPickingInfo\n} from './bitmap-layer/bitmap-layer';\nexport type {ColumnLayerProps} from './column-layer/column-layer';\nexport type {ScatterplotLayerProps} from './scatterplot-layer/scatterplot-layer';\nexport type {IconLayerProps} from './icon-layer/icon-layer';\nexport type {LineLayerProps} from './line-layer/line-layer';\nexport type {PolygonLayerProps} from './polygon-layer/polygon-layer';\nexport type {GeoJsonLayerProps} from './geojson-layer/geojson-layer';\nexport type {GridCellLayerProps} from './column-layer/grid-cell-layer';\nexport type {TextLayerProps} from './text-layer/text-layer';\nexport type {MultiIconLayerProps} from './text-layer/multi-icon-layer/multi-icon-layer';\nexport type {PointCloudLayerProps} from './point-cloud-layer/point-cloud-layer';\nexport type {TextBackgroundLayerProps} from './text-layer/text-background-layer/text-background-layer';\nexport type {PathLayerProps} from './path-layer/path-layer';\nexport type {SolidPolygonLayerProps} from './solid-polygon-layer/solid-polygon-layer';\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {\n Layer,\n project32,\n picking,\n UNIT,\n UpdateParameters,\n LayerProps,\n LayerDataSource,\n Unit,\n AccessorFunction,\n Position,\n Accessor,\n Color,\n DefaultProps\n} from '@deck.gl/core';\n\nimport {Model} from '@luma.gl/engine';\n\nimport {arcUniforms, ArcProps} from './arc-layer-uniforms';\nimport vs from './arc-layer-vertex.glsl';\nimport fs from './arc-layer-fragment.glsl';\n\nconst DEFAULT_COLOR: [number, number, number, number] = [0, 0, 0, 255];\n\nconst defaultProps: DefaultProps<ArcLayerProps> = {\n getSourcePosition: {type: 'accessor', value: (x: any) => x.sourcePosition},\n getTargetPosition: {type: 'accessor', value: (x: any) => x.targetPosition},\n getSourceColor: {type: 'accessor', value: DEFAULT_COLOR},\n getTargetColor: {type: 'accessor', value: DEFAULT_COLOR},\n getWidth: {type: 'accessor', value: 1},\n getHeight: {type: 'accessor', value: 1},\n getTilt: {type: 'accessor', value: 0},\n\n greatCircle: false,\n numSegments: {type: 'number', value: 50, min: 1},\n\n widthUnits: 'pixels',\n widthScale: {type: 'number', value: 1, min: 0},\n widthMinPixels: {type: 'number', value: 0, min: 0},\n widthMaxPixels: {type: 'number', value: Number.MAX_SAFE_INTEGER, min: 0}\n};\n\n/** All properties supported by ArcLayer. */\nexport type ArcLayerProps<DataT = unknown> = _ArcLayerProps<DataT> & LayerProps;\n\n/** Properties added by ArcLayer. */\ntype _ArcLayerProps<DataT> = {\n data: LayerDataSource<DataT>;\n /**\n * If `true`, create the arc along the shortest path on the earth surface.\n * @default false\n */\n greatCircle?: boolean;\n\n /**\n * The number of segments used to draw each arc.\n * @default 50\n */\n numSegments?: number;\n\n /**\n * The units of the line width, one of `'meters'`, `'common'`, and `'pixels'`\n * @default 'pixels'\n */\n widthUnits?: Unit;\n\n /**\n * The scaling multiplier for the width of each line.\n * @default 1\n */\n widthScale?: number;\n\n /**\n * The minimum line width in pixels.\n * @default 0\n */\n widthMinPixels?: number;\n\n /**\n * The maximum line width in pixels.\n * @default Number.MAX_SAFE_INTEGER\n */\n widthMaxPixels?: number;\n\n /**\n * Method called to retrieve the source position of each object.\n * @default object => object.sourcePosition\n */\n getSourcePosition?: AccessorFunction<DataT, Position>;\n\n /**\n * Method called to retrieve the target position of each object.\n * @default object => object.targetPosition\n */\n getTargetPosition?: AccessorFunction<DataT, Position>;\n\n /**\n * The rgba color is in the format of `[r, g, b, [a]]`.\n * @default [0, 0, 0, 255]\n */\n getSourceColor?: Accessor<DataT, Color>;\n\n /**\n * The rgba color is in the format of `[r, g, b, [a]]`.\n * @default [0, 0, 0, 255]\n */\n getTargetColor?: Accessor<DataT, Color>;\n\n /**\n * The line width of each object, in units specified by `widthUnits`.\n * @default 1\n */\n getWidth?: Accessor<DataT, number>;\n\n /**\n * Multiplier of layer height. `0` will make the layer flat.\n * @default 1\n */\n getHeight?: Accessor<DataT, number>;\n\n /**\n * Use to tilt the arc to the side if you have multiple arcs with the same source and target positions.\n * @default 0\n */\n getTilt?: Accessor<DataT, number>;\n};\n\n/** Render raised arcs joining pairs of source and target coordinates. */\nexport default class ArcLayer<DataT = any, ExtraPropsT extends {} = {}> extends Layer<\n ExtraPropsT & Required<_ArcLayerProps<DataT>>\n> {\n static layerName = 'ArcLayer';\n static defaultProps = defaultProps;\n\n state!: {\n model?: Model;\n };\n\n getBounds(): [number[], number[]] | null {\n return this.getAttributeManager()?.getBounds([\n 'instanceSourcePositions',\n 'instanceTargetPositions'\n ]);\n }\n\n getShaders() {\n return super.getShaders({vs, fs, modules: [project32, picking, arcUniforms]}); // 'project' module added by default.\n }\n\n // This layer has its own wrapLongitude logic\n get wrapLongitude() {\n return false;\n }\n\n initializeState() {\n const attributeManager = this.getAttributeManager()!;\n\n /* eslint-disable max-len */\n attributeManager.addInstanced({\n instanceSourcePositions: {\n size: 3,\n type: 'float64',\n fp64: this.use64bitPositions(),\n transition: true,\n accessor: 'getSourcePosition'\n },\n instanceTargetPositions: {\n size: 3,\n type: 'float64',\n fp64: this.use64bitPositions(),\n transition: true,\n accessor: 'getTargetPosition'\n },\n instanceSourceColors: {\n size: this.props.colorFormat.length,\n type: 'unorm8',\n transition: true,\n accessor: 'getSourceColor',\n defaultValue: DEFAULT_COLOR\n },\n instanceTargetColors: {\n size: this.props.colorFormat.length,\n type: 'unorm8',\n transition: true,\n accessor: 'getTargetColor',\n defaultValue: DEFAULT_COLOR\n },\n instanceWidths: {\n size: 1,\n transition: true,\n accessor: 'getWidth',\n defaultValue: 1\n },\n instanceHeights: {\n size: 1,\n transition: true,\n accessor: 'getHeight',\n defaultValue: 1\n },\n instanceTilts: {\n size: 1,\n transition: true,\n accessor: 'getTilt',\n defaultValue: 0\n }\n });\n /* eslint-enable max-len */\n }\n\n updateState(params: UpdateParameters<this>): void {\n super.updateState(params);\n\n if (params.changeFlags.extensionsChanged) {\n this.state.model?.destroy();\n this.state.model = this._getModel();\n this.getAttributeManager()!.invalidateAll();\n }\n }\n\n draw({uniforms}) {\n const {\n widthUnits,\n widthScale,\n widthMinPixels,\n widthMaxPixels,\n greatCircle,\n wrapLongitude,\n numSegments\n } = this.props;\n const arcProps: ArcProps = {\n numSegments,\n widthUnits: UNIT[widthUnits],\n widthScale,\n widthMinPixels,\n widthMaxPixels,\n greatCircle,\n useShortestPath: wrapLongitude\n };\n\n const model = this.state.model!;\n model.shaderInputs.setProps({arc: arcProps});\n model.setVertexCount(numSegments * 2);\n model.draw(this.context.renderPass);\n }\n\n protected _getModel(): Model {\n return new Model(this.context.device, {\n ...this.getShaders(),\n id: this.props.id,\n bufferLayout: this.getAttributeManager()!.getBufferLayouts(),\n topology: 'triangle-strip',\n isInstanced: true\n });\n }\n}\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {ShaderModule} from '@luma.gl/shadertools';\n\nconst uniformBlock = `\\\nuniform arcUniforms {\n bool greatCircle;\n bool useShortestPath;\n float numSegments;\n float widthScale;\n float widthMinPixels;\n float widthMaxPixels;\n highp int widthUnits;\n} arc;\n`;\n\nexport type ArcProps = {\n greatCircle: boolean;\n useShortestPath: boolean;\n numSegments: number;\n widthScale: number;\n widthMinPixels: number;\n widthMaxPixels: number;\n widthUnits: number;\n};\n\nexport const arcUniforms = {\n name: 'arc',\n vs: uniformBlock,\n fs: uniformBlock,\n uniformTypes: {\n greatCircle: 'f32',\n useShortestPath: 'f32',\n numSegments: 'f32',\n widthScale: 'f32',\n widthMinPixels: 'f32',\n widthMaxPixels: 'f32',\n widthUnits: 'i32'\n }\n} as const satisfies ShaderModule<ArcProps>;\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nexport default `\\\n#version 300 es\n#define SHADER_NAME arc-layer-vertex-shader\n\nin vec4 instanceSourceColors;\nin vec4 instanceTargetColors;\nin vec3 instanceSourcePositions;\nin vec3 instanceSourcePositions64Low;\nin vec3 instanceTargetPositions;\nin vec3 instanceTargetPositions64Low;\nin vec3 instancePickingColors;\nin float instanceWidths;\nin float instanceHeights;\nin float instanceTilts;\n\nout vec4 vColor;\nout vec2 uv;\nout float isValid;\n\nfloat paraboloid(float distance, float sourceZ, float targetZ, float ratio) {\n // d: distance on the xy plane\n // r: ratio of the current point\n // p: ratio of the peak of the arc\n // h: height multiplier\n // z = f(r) = sqrt(r * (p * 2 - r)) * d * h\n // f(0) = 0\n // f(1) = dz\n\n float deltaZ = targetZ - sourceZ;\n float dh = distance * instanceHeights;\n if (dh == 0.0) {\n return sourceZ + deltaZ * ratio;\n }\n float unitZ = deltaZ / dh;\n float p2 = unitZ * unitZ + 1.0;\n\n // sqrt does not deal with negative values, manually flip source and target if delta.z < 0\n float dir = step(deltaZ, 0.0);\n float z0 = mix(sourceZ, targetZ, dir);\n float r = mix(ratio, 1.0 - ratio, dir);\n return sqrt(r * (p2 - r)) * dh + z0;\n}\n\n// offset vector by strokeWidth pixels\n// offset_direction is -1 (left) or 1 (right)\nvec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction, float width) {\n // normalized direction of the line\n vec2 dir_screenspace = normalize(line_clipspace * project.viewportSize);\n // rotate by 90 degrees\n dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);\n\n return dir_screenspace * offset_direction * width / 2.0;\n}\n\nfloat getSegmentRatio(float index) {\n return smoothstep(0.0, 1.0, index / (arc.numSegments - 1.0));\n}\n\nvec3 interpolateFlat(vec3 source, vec3 target, float segmentRatio) {\n float distance = length(source.xy - target.xy);\n float z = paraboloid(distance, source.z, target.z, segmentRatio);\n\n float tiltAngle = radians(instanceTilts);\n vec2 tiltDirection = normalize(target.xy - source.xy);\n vec2 tilt = vec2(-tiltDirection.y, tiltDirection.x) * z * sin(tiltAngle);\n\n return vec3(\n mix(source.xy, target.xy, segmentRatio) + tilt,\n z * cos(tiltAngle)\n );\n}\n\n/* Great circle interpolation\n * http://www.movable-type.co.uk/scripts/latlong.html\n */\nfloat getAngularDist (vec2 source, vec2 target) {\n vec2 sourceRadians = radians(source);\n vec2 targetRadians = radians(target);\n vec2 sin_half_delta = sin((sourceRadians - targetRadians) / 2.0);\n vec2 shd_sq = sin_half_delta * sin_half_delta;\n\n float a = shd_sq.y + cos(sourceRadians.y) * cos(targetRadians.y) * shd_sq.x;\n return 2.0 * asin(sqrt(a));\n}\n\nvec3 interpolateGreatCircle(vec3 source, vec3 target, vec3 source3D, vec3 target3D, float angularDist, float t) {\n vec2 lngLat;\n\n // if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation\n if(abs(angularDist - PI) < 0.001) {\n lngLat = (1.0 - t) * source.xy + t * target.xy;\n } else {\n float a = sin((1.0 - t) * angularDist);\n float b = sin(t * angularDist);\n vec3 p = source3D.yxz * a + target3D.yxz * b;\n lngLat = degrees(vec2(atan(p.y, -p.x), atan(p.z, length(p.xy))));\n }\n\n float z = paraboloid(angularDist * EARTH_RADIUS, source.z, target.z, t);\n\n return vec3(lngLat, z);\n}\n\n/* END GREAT CIRCLE */\n\nvoid main(void) {\n geometry.worldPosition = instanceSourcePositions;\n geometry.worldPositionAlt = instanceTargetPositions;\n\n /*\n * --(i, -1)-----------_(i+1, -1)--\n * | _,-\" |\n * o _,-\" o\n * | _,-\" |\n * --(i, 1)\"-------------(i+1, 1)--\n */\n float segmentIndex = float(gl_VertexID / 2);\n float segmentSide = mod(float(gl_VertexID), 2.) == 0. ? -1. : 1.;\n float segmentRatio = getSegmentRatio(segmentIndex);\n float prevSegmentRatio = getSegmentRatio(max(0.0, segmentIndex - 1.0));\n float nextSegmentRatio = getSegmentRatio(min(arc.numSegments - 1.0, segmentIndex + 1.0));\n\n // if it's the first point, use next - current as direction\n // otherwise use current - prev\n float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));\n isValid = 1.0;\n\n uv = vec2(segmentRatio, segmentSide);\n geometry.uv = uv;\n geometry.pickingColor = instancePickingColors;\n\n vec4 curr;\n vec4 next;\n vec3 source;\n vec3 target;\n\n if ((arc.greatCircle || project.projectionMode == PROJECTION_MODE_GLOBE) && project.coordinateSystem == COORDINATE_SYSTEM_LNGLAT) {\n source = project_globe_(vec3(instanceSourcePositions.xy, 0.0));\n target = project_globe_(vec3(instanceTargetPositions.xy, 0.0));\n float angularDist = getAngularDist(instanceSourcePositions.xy, instanceTargetPositions.xy);\n\n vec3 prevPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, prevSegmentRatio);\n vec3 currPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, segmentRatio);\n vec3 nextPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, nextSegmentRatio);\n\n if (abs(currPos.x - prevPos.x) > 180.0) {\n indexDir = -1.0;\n isValid = 0.0;\n } else if (abs(currPos.x - nextPos.x) > 180.0) {\n indexDir = 1.0;\n isValid = 0.0;\n }\n nextPos = indexDir < 0.0 ? prevPos : nextPos;\n nextSegmentRatio = indexDir < 0.0 ? prevSegmentRatio : nextSegmentRatio;\n\n if (isValid == 0.0) {\n // split at the 180th meridian\n nextPos.x += nextPos.x > 0.0 ? -360.0 : 360.0;\n float t = ((currPos.x > 0.0 ? 180.0 : -180.0) - currPos.x) / (nextPos.x - currPos.x);\n currPos = mix(currPos, nextPos, t);\n segmentRatio = mix(segmentRatio, nextSegmentRatio, t);\n }\n\n vec3 currPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, segmentRatio);\n vec3 nextPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, nextSegmentRatio);\n \n curr = project_position_to_clipspace(currPos, currPos64Low, vec3(0.0), geometry.position);\n next = project_position_to_clipspace(nextPos, nextPos64Low, vec3(0.0));\n \n } else {\n vec3 source_world = instanceSourcePositions;\n vec3 target_world = instanceTargetPositions;\n if (arc.useShortestPath) {\n source_world.x = mod(source_world.x + 180., 360.0) - 180.;\n target_world.x = mod(target_world.x + 180., 360.0) - 180.;\n\n float deltaLng = target_world.x - source_world.x;\n if (deltaLng > 180.) target_world.x -= 360.;\n if (deltaLng < -180.) source_world.x -= 360.;\n }\n source = project_position(source_world, instanceSourcePositions64Low);\n target = project_position(target_world, instanceTargetPositions64Low);\n\n // common x at longitude=-180\n float antiMeridianX = 0.0;\n\n if (arc.useShortestPath) {\n if (project.projectionMode == PROJECTION_MODE_WEB_MERCATOR_AUTO_OFFSET) {\n antiMeridianX = -(project.coordinateOrigin.x + 180.) / 360. * TILE_SIZE;\n }\n float thresholdRatio = (antiMeridianX - source.x) / (target.x - source.x);\n\n if (prevSegmentRatio <= thresholdRatio && nextSegmentRatio > thresholdRatio) {\n isValid = 0.0;\n indexDir = sign(segmentRatio - thresholdRatio);\n segmentRatio = thresholdRatio;\n }\n }\n\n nextSegmentRatio = indexDir < 0.0 ? prevSegmentRatio : nextSegmentRatio;\n vec3 currPos = interpolateFlat(source, target, segmentRatio);\n vec3 nextPos = interpolateFlat(source, target, nextSegmentRatio);\n\n if (arc.useShortestPath) {\n if (nextPos.x < antiMeridianX) {\n currPos.x += TILE_SIZE;\n nextPos.x += TILE_SIZE;\n }\n }\n\n curr = project_common_position_to_clipspace(vec4(currPos, 1.0));\n next = project_common_position_to_clipspace(vec4(nextPos, 1.0));\n geometry.position = vec4(currPos, 1.0);\n }\n\n // Multiply out width and clamp to limits\n // mercator pixels are interpreted as screen pixels\n float widthPixels = clamp(\n project_size_to_pixel(instanceWidths * arc.widthScale, arc.widthUnits),\n arc.widthMinPixels, arc.widthMaxPixels\n );\n\n // extrude\n vec3 offset = vec3(\n getExtrusionOffset((next.xy - curr.xy) * indexDir, segmentSide, widthPixels),\n 0.0);\n DECKGL_FILTER_SIZE(offset, geometry);\n DECKGL_FILTER_GL_POSITION(curr, geometry);\n gl_Position = curr + vec4(project_pixel_size_to_clipspace(offset.xy), 0.0, 0.0);\n\n vec4 color = mix(instanceSourceColors, instanceTargetColors, segmentRatio);\n vColor = vec4(color.rgb, color.a * layer.opacity);\n DECKGL_FILTER_COLOR(vColor, geometry);\n}\n`;\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nexport default `\\\n#version 300 es\n#define SHADER_NAME arc-layer-fragment-shader\n\nprecision highp float;\n\nin vec4 vColor;\nin vec2 uv;\nin float isValid;\n\nout vec4 fragColor;\n\nvoid main(void) {\n if (isValid == 0.0) {\n discard;\n }\n\n fragColor = vColor;\n geometry.uv = uv;\n\n DECKGL_FILTER_COLOR(fragColor, geometry);\n}\n`;\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {\n Layer,\n project32,\n picking,\n CoordinateSystem,\n COORDINATE_SYSTEM,\n LayerProps,\n PickingInfo,\n GetPickingInfoParams,\n UpdateParameters,\n Color,\n TextureSource,\n Position,\n DefaultProps\n} from '@deck.gl/core';\nimport {Model} from '@luma.gl/engine';\nimport type {SamplerProps, Texture} from '@luma.gl/core';\nimport {lngLatToWorld} from '@math.gl/web-mercator';\n\nimport createMesh from './create-mesh';\n\nimport {bitmapUniforms, BitmapProps} from './bitmap-layer-uniforms';\nimport vs from './bitmap-layer-vertex';\nimport fs from './bitmap-layer-fragment';\n\nconst defaultProps: DefaultProps<BitmapLayerProps> = {\n image: {type: 'image', value: null, async: true},\n bounds: {type: 'array', value: [1, 0, 0, 1], compare: true},\n _imageCoordinateSystem: COORDINATE_SYSTEM.DEFAULT,\n\n desaturate: {type: 'number', min: 0, max: 1, value: 0},\n // More context: because of the blending mode we're using for ground imagery,\n // alpha is not effective when blending the bitmap layers with the base map.\n // Instead we need to manually dim/blend rgb values with a background color.\n transparentColor: {type: 'color', value: [0, 0, 0, 0]},\n tintColor: {type: 'color', value: [255, 255, 255]},\n\n textureParameters: {type: 'object', ignore: true, value: null}\n};\n\n/** All properties supported by BitmapLayer. */\nexport type BitmapLayerProps = _BitmapLayerProps & LayerProps;\nexport type BitmapBoundingBox =\n | [left: number, bottom: number, right: number, top: number]\n | [Position, Position, Position, Position];\n\n/** Properties added by BitmapLayer. */\ntype _BitmapLayerProps = {\n data: never;\n /**\n * The image to display.\n *\n * @default null\n */\n image?: string | TextureSource | null;\n\n /**\n * Supported formats:\n * - Coordinates of the bounding box of the bitmap `[left, bottom, right, top]`\n * - Coordinates of four corners of the bitmap, should follow the sequence of `[[left, bottom], [left, top], [right, top], [right, bottom]]`.\n * Each position could optionally contain a third component `z`.\n * @default [1, 0, 0, 1]\n */\n bounds?: BitmapBoundingBox;\n\n /**\n * > Note: this prop is experimental.\n *\n * Specifies how image coordinates should be geographically interpreted.\n * @default COORDINATE_SYSTEM.DEFAULT\n */\n _imageCoordinateSystem?: CoordinateSystem;\n\n /**\n * The desaturation of the bitmap. Between `[0, 1]`.\n * @default 0\n */\n desaturate?: number;\n\n /**\n * The color to use for transparent pixels, in `[r, g, b, a]`.\n * @default [0, 0, 0, 0]\n */\n transparentColor?: Color;\n\n /**\n * The color to tint the bitmap by, in `[r, g, b]`.\n * @default [255, 255, 255]\n */\n tintColor?: Color;\n\n /** Customize the [texture parameters](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texParameter). */\n textureParameters?: SamplerProps | null;\n};\n\nexport type BitmapLayerPickingInfo = PickingInfo<\n null,\n {\n bitmap: {\n /** Size of the original image */\n size: {\n width: number;\n height: number;\n };\n /** Hovered pixel uv in 0-1 range */\n uv: [number, number];\n /** Hovered pixel in the original image */\n pixel: [number, number];\n } | null;\n }\n>;\n\n/** Render a bitmap at specified boundaries. */\nexport default class BitmapLayer<ExtraPropsT extends {} = {}> extends Layer<\n ExtraPropsT & Required<_BitmapLayerProps>\n> {\n static layerName = 'BitmapLayer';\n static defaultProps = defaultProps;\n\n state!: {\n disablePicking?: boolean;\n model?: Model;\n mesh?: any;\n coordinateConversion: number;\n bounds: [number, number, number, number];\n };\n\n getShaders() {\n return super.getShaders({vs, fs, modules: [project32, picking, bitmapUniforms]});\n }\n\n initializeState() {\n const attributeManager = this.getAttributeManager()!;\n\n attributeManager.remove(['instancePickingColors']);\n const noAlloc = true;\n\n attributeManager.add({\n indices: {\n size: 1,\n isIndexed: true,\n update: attribute => (attribute.value = this.state.mesh.indices),\n noAlloc\n },\n positions: {\n size: 3,\n type: 'float64',\n fp64: this.use64bitPositions(),\n update: attribute => (attribute.value = this.state.mesh.positions),\n noAlloc\n },\n texCoords: {\n size: 2,\n update: attribute => (attribute.value = this.state.mesh.texCoords),\n noAlloc\n }\n });\n }\n\n updateState({props, oldProps, changeFlags}: UpdateParameters<this>): void {\n // setup model first\n const attributeManager = this.getAttributeManager()!;\n\n if (changeFlags.extensionsChanged) {\n this.state.model?.destroy();\n this.state.model = this._getModel();\n attributeManager.invalidateAll();\n }\n\n if (props.bounds !== oldProps.bounds) {\n const oldMesh = this.state.mesh;\n const mesh = this._createMesh();\n this.state.model!.setVertexCount(mesh.vertexCount);\n for (const key in mesh) {\n if (oldMesh && oldMesh[key] !== mesh[key]) {\n attributeManager.invalidate(key);\n }\n }\n this.setState({mesh, ...this._getCoordinateUniforms()});\n } else if (props._imageCoordinateSystem !== oldProps._imageCoordinateSystem) {\n this.setState(this._getCoordinateUniforms());\n }\n }\n\n getPickingInfo(params: GetPickingInfoParams): BitmapLayerPickingInfo {\n const {image} = this.props;\n const info = params.info as BitmapLayerPickingInfo;\n\n if (!info.color || !image) {\n info.bitmap = null;\n return info;\n }\n\n const {width, height} = image as Texture;\n\n // Picking color doesn't represent object index in this layer\n info.index = 0;\n\n // Calculate uv and pixel in bitmap\n const uv = unpackUVsFromRGB(info.color);\n\n info.bitmap = {\n size: {width, height},\n uv,\n pixel: [Math.floor(uv[0] * width), Math.floor(uv[1] * height)]\n };\n\n return info;\n }\n\n // Override base Layer multi-depth picking logic\n disablePickingIndex() {\n this.setState({disablePicking: true});\n }\n\n restorePickingColors() {\n this.setState({disablePicking: false});\n }\n\n protected _updateAutoHighlight(info) {\n super._updateAutoHighlight({\n ...info,\n color: this.encodePickingColor(0)\n });\n }\n\n protected _createMesh() {\n const {bounds} = this.props;\n\n let normalizedBounds = bounds;\n // bounds as [minX, minY, maxX, maxY]\n if (isRectangularBounds(bounds)) {\n /*\n (minX0, maxY3) ---- (maxX2, maxY3)\n | |\n | |\n | |\n (minX0, minY1) ---- (maxX2, minY1)\n */\n normalizedBounds = [\n [bounds[0], bounds[1]],\n [bounds[0], bounds[3]],\n [bounds[2], bounds[3]],\n [bounds[2], bounds[1]]\n ];\n }\n\n return createMesh(normalizedBounds, this.context.viewport.resolution);\n }\n\n protected _getModel(): Model {\n /*\n 0,0 --- 1,0\n | |\n 0,1 --- 1,1\n */\n return new Model(this.context.device, {\n ...this.getShaders(),\n id: this.props.id,\n bufferLayout: this.getAttributeManager()!.getBufferLayouts(),\n topology: 'triangle-list',\n isInstanced: false\n });\n }\n\n draw(opts) {\n const {shaderModuleProps} = opts;\n const {model, coordinateConversion, bounds, disablePicking} = this.state;\n const {image, desaturate, transparentColor, tintColor} = this.props;\n\n if (shaderModuleProps.picking.isActive && disablePicking) {\n return;\n }\n\n // // TODO fix zFighting\n // Render the image\n if (image && model) {\n const bitmapProps: BitmapProps = {\n bitmapTexture: image as Texture,\n bounds,\n coordinateConversion,\n desaturate,\n tintColor: tintColor.slice(0, 3).map(x => x / 255) as [number, number, number],\n transparentColor: transparentColor.map(x => x / 255) as [number, number, number, number]\n };\n model.shaderInputs.setProps({bitmap: bitmapProps});\n model.draw(this.context.renderPass);\n }\n }\n\n _getCoordinateUniforms() {\n const {LNGLAT, CARTESIAN, DEFAULT} = COORDINATE_SYSTEM;\n let {_imageCoordinateSystem: imageCoordinateSystem} = this.props;\n if (imageCoordinateSystem !== DEFAULT) {\n const {bounds} = this.props;\n if (!isRectangularBounds(bounds)) {\n throw new Error('_imageCoordinateSystem only supports rectangular bounds');\n }\n\n // The default behavior (linearly interpolated tex coords)\n const defaultImageCoordinateSystem = this.context.viewport.resolution ? LNGLAT : CARTESIAN;\n imageCoordinateSystem = imageCoordinateSystem === LNGLAT ? LNGLAT : CARTESIAN;\n\n if (imageCoordinateSystem === LNGLAT && defaultImageCoordinateSystem === CARTESIAN) {\n // LNGLAT in Mercator, e.g. display LNGLAT-encoded image in WebMercator projection\n return {coordinateConversion: -1, bounds};\n }\n if (imageCoordinateSystem === CARTESIAN && defaultImageCoordinateSystem === LNGLAT) {\n // Mercator in LNGLAT, e.g. display WebMercator encoded image in Globe projection\n const bottomLeft = lngLatToWorld([bounds[0], bounds[1]]);\n const topRight = lngLatToWorld([bounds[2], bounds[3]]);\n return {\n coordinateConversion: 1,\n bounds: [bottomLeft[0], bottomLeft[1], topRight[0], topRight[1]]\n };\n }\n }\n return {\n coordinateConversion: 0,\n bounds: [0, 0, 0, 0]\n };\n }\n}\n\n/**\n * Decode uv floats from rgb bytes where b contains 4-bit fractions of uv\n * @param {number[]} color\n * @returns {number[]} uvs\n * https://stackoverflow.com/questions/30242013/glsl-compressing-packing-multiple-0-1-colours-var4-into-a-single-var4-variab\n */\nfunction unpackUVsFromRGB(color: Uint8Array): [number, number] {\n const [u, v, fracUV] = color;\n const vFrac = (fracUV & 0xf0) / 256;\n const uFrac = (fracUV & 0x0f) / 16;\n return [(u + uFrac) / 256, (v + vFrac) / 256];\n}\n\nfunction isRectangularBounds(\n bounds: [number, number, number, number] | [Position, Position, Position, Position]\n): bounds is [number, number, number, number] {\n return Number.isFinite(bounds[0]);\n}\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {lerp} from '@math.gl/core';\n\nconst DEFAULT_INDICES = new Uint32Array([0, 2, 1, 0, 3, 2]);\nconst DEFAULT_TEX_COORDS = new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]);\n\n/*\n 1 ---- 2\n | |\n | |\n 0 ---- 3\n*/\n/* eslint-disable max-statements */\nexport default function createMesh(bounds, resolution) {\n if (!resolution) {\n return createQuad(bounds);\n }\n const maxXSpan = Math.max(\n Math.abs(bounds[0][0] - bounds[3][0]),\n Math.abs(bounds[1][0] - bounds[2][0])\n );\n const maxYSpan = Math.max(\n Math.abs(bounds[1][1] - bounds[0][1]),\n Math.abs(bounds[2][1] - bounds[3][1])\n );\n const uCount = Math.ceil(maxXSpan / resolution) + 1;\n const vCount = Math.ceil(maxYSpan / resolution) + 1;\n\n const vertexCount = (uCount - 1) * (vCount - 1) * 6;\n const indices = new Uint32Array(vertexCount);\n const texCoords = new Float32Array(uCount * vCount * 2);\n const positions = new Float64Array(uCount * vCount * 3);\n\n // Tesselate\n let vertex = 0;\n let index = 0;\n for (let u = 0; u < uCount; u++) {\n const ut = u / (uCount - 1);\n for (let v = 0; v < vCount; v++) {\n const vt = v / (vCount - 1);\n const p = interpolateQuad(bounds, ut, vt);\n\n positions[vertex * 3 + 0] = p[0];\n positions[vertex * 3 + 1] = p[1];\n positions[vertex * 3 + 2] = p[2] || 0;\n\n texCoords[vertex * 2 + 0] = ut;\n texCoords[vertex * 2 + 1] = 1 - vt;\n\n if (u > 0 && v > 0) {\n indices[index++] = vertex - vCount;\n indices[index++] = vertex - vCount - 1;\n indices[index++] = vertex - 1;\n indices[index++] = vertex - vCount;\n indices[index++] = vertex - 1;\n indices[index++] = vertex;\n }\n\n vertex++;\n }\n }\n return {\n vertexCount,\n positions,\n indices,\n texCoords\n };\n}\n\nfunction createQuad(bounds) {\n const positions = new Float64Array(12);\n // [[minX, minY], [minX, maxY], [maxX, maxY], [maxX, minY]]\n for (let i = 0; i < bounds.length; i++) {\n positions[i * 3 + 0] = bounds[i][0];\n positions[i * 3 + 1] = bounds[i][1];\n positions[i * 3 + 2] = bounds[i][2] || 0;\n }\n\n return {\n vertexCount: 6,\n positions,\n indices: DEFAULT_INDICES,\n texCoords: DEFAULT_TEX_COORDS\n };\n}\n\nfunction interpolateQuad(quad, ut, vt) {\n return lerp(lerp(quad[0], quad[1], vt), lerp(quad[3], quad[2], vt), ut);\n}\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {Texture} from '@luma.gl/core';\nimport type {ShaderModule} from '@luma.gl/shadertools';\n\nconst uniformBlock = `\\\nuniform bitmapUniforms {\n vec4 bounds;\n float coordinateConversion;\n float desaturate;\n vec3 tintColor;\n vec4 transparentColor;\n} bitmap;\n`;\n\nexport type BitmapProps = {\n bounds: [number, number, number, number];\n coordinateConversion: number;\n desaturate: number;\n tintColor: [number, number, number];\n transparentColor: [number, number, number, number];\n bitmapTexture: Texture;\n};\n\nexport const bitmapUniforms = {\n name: 'bitmap',\n vs: uniformBlock,\n fs: uniformBlock,\n uniformTypes: {\n bounds: 'vec4<f32>',\n coordinateConversion: 'f32',\n desaturate: 'f32',\n tintColor: 'vec3<f32>',\n transparentColor: 'vec4<f32>'\n }\n} as const satisfies ShaderModule<BitmapProps>;\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nexport default `\\\n#version 300 es\n#define SHADER_NAME bitmap-layer-vertex-shader\n\nin vec2 texCoords;\nin vec3 positions;\nin vec3 positions64Low;\n\nout vec2 vTexCoord;\nout vec2 vTexPos;\n\nconst vec3 pickingColor = vec3(1.0, 0.0, 0.0);\n\nvoid main(void) {\n geometry.worldPosition = positions;\n geometry.uv = texCoords;\n geometry.pickingColor = pickingColor;\n\n gl_Position = project_position_to_clipspace(positions, positions64Low, vec3(0.0), geometry.position);\n DECKGL_FILTER_GL_POSITION(gl_Position, geometry);\n\n vTexCoord = texCoords;\n\n if (bitmap.coordinateConversion < -0.5) {\n vTexPos = geometry.position.xy + project.commonOrigin.xy;\n } else if (bitmap.coordinateConversion > 0.5) {\n vTexPos = geometry.worldPosition.xy;\n }\n\n vec4 color = vec4(0.0);\n DECKGL_FILTER_COLOR(color, geometry);\n}\n`;\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n/**\n * Pack the top 12 bits of two normalized floats into 3 8-bit (rgb) values\n * This enables addressing 4096x4096 individual pixels\n *\n * returns vec3 encoded RGB colors\n * result.r - top 8 bits of u\n * result.g - top 8 bits of v\n * result.b - next 4 bits of u and v: (u + v * 16)\n */\nconst packUVsIntoRGB = `\nvec3 packUVsIntoRGB(vec2 uv) {\n // Extract the top 8 bits. We want values to be truncated down so we can add a fraction\n vec2 uv8bit = floor(uv * 256.);\n\n // Calculate the normalized remainders of u and v parts that do not fit into 8 bits\n // Scale and clamp to 0-1 range\n vec2 uvFraction = fract(uv * 256.);\n vec2 uvFraction4bit = floor(uvFraction * 16.);\n\n // Remainder can be encoded in blue channel, encode as 4 bits for pixel coordinates\n float fractions = uvFraction4bit.x + uvFraction4bit.y * 16.;\n\n return vec3(uv8bit, fractions) / 255.;\n}\n`;\n\nexport default `\\\n#version 300 es\n#define SHADER_NAME bitmap-layer-fragment-shader\n\n#ifdef GL_ES\nprecision highp float;\n#endif\n\nuniform sampler2D bitmapTexture;\n\nin vec2 vTexCoord;\nin vec2 vTexPos;\n\nout vec4 fragColor;\n\n/* projection utils */\nconst float TILE_SIZE = 512.0;\nconst float PI = 3.1415926536;\nconst float WORLD_SCALE = TILE_SIZE / PI / 2.0;\n\n// from degrees to Web Mercator\nvec2 lnglat_to_mercator(vec2 lnglat) {\n float x = lnglat.x;\n float y = clamp(lnglat.y, -89.9, 89.9);\n return vec2(\n radians(x) + PI,\n PI + log(tan(PI * 0.25 + radians(y) * 0.5))\n ) * WORLD_SCALE;\n}\n\n// from Web Mercator to degrees\nvec2 mercator_to_lnglat(vec2 xy) {\n xy /= WORLD_SCALE;\n return degrees(vec2(\n xy.x - PI,\n atan(exp(xy.y - PI)) * 2.0 - PI * 0.5\n ));\n}\n/* End projection utils */\n\n// apply desaturation\nvec3 color_desaturate(vec3 color) {\n float luminance = (color.r + color.g + color.b) * 0.333333333;\n return mix(color, vec3(luminance), bitmap.desaturate);\n}\n\n// apply tint\nvec3 color_tint(vec3 color) {\n return color * bitmap.tintColor;\n}\n\n// blend with background color\nvec4 apply_opacity(vec3 color, float alpha) {\n if (bitmap.transparentColor.a == 0.0) {\n return vec4(color, alpha);\n }\n float blendedAlpha = alpha + bitmap.transparentColor.a * (1.0 - alpha);\n float highLightRatio = alpha / blendedAlpha;\n vec3 blendedRGB = mix(bitmap.transparentColor.rgb, color, highLightRatio);\n return vec4(blendedRGB, blendedAlpha);\n}\n\nvec2 getUV(vec2 pos) {\n return vec2(\n (pos.x - bitmap.bounds[0]) / (bitmap.bounds[2] - bitmap.bounds[0]),\n (pos.y - bitmap.bounds[3]) / (bitmap.bounds[1] - bitmap.bounds[3])\n );\n}\n\n${packUVsIntoRGB}\n\nvoid main(void) {\n vec2 uv = vTexCoord;\n if (bitmap.coordinateConversion < -0.5) {\n vec2 lnglat = mercator_to_lnglat(vTexPos);\n uv = getUV(lnglat);\n } else if (bitmap.coordinateConversion > 0.5) {\n vec2 commonPos = lnglat_to_mercator(vTexPos);\n uv = getUV(commonPos);\n }\n vec4 bitmapColor = texture(bitmapTexture, uv);\n\n fragColor = apply_opacity(color_tint(color_desaturate(bitmapColor.rgb)), bitmapColor.a * layer.opacity);\n\n geometry.uv = uv;\n DECKGL_FILTER_COLOR(fragColor, geometry);\n\n if (bool(picking.isActive) && !bool(picking.isAttribute)) {\n // Since instance information is not used, we can use picking color for pixel index\n fragColor.rgb = packUVsIntoRGB(uv);\n }\n}\n`;\n", "// deck.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {Layer, project32, picking, log, UNIT} from '@deck.gl/core';\nimport {SamplerProps, Texture} from '@luma.gl/core';\nimport {Model, Geometry} from '@luma.gl/engine';\n\nimport {iconUniforms, IconProps} from './icon-layer-uniforms';\nimport vs from './icon-layer-vertex.glsl';\nimport fs from './icon-layer-fragment.glsl';\nimport IconManager from './icon-manager';\n\nimport type {\n LayerProps,\n LayerDataSource,\n Accessor,\n AccessorFunction,\n Position,\n Color,\n Unit,\n UpdateParameters,\n LayerContext,\n DefaultProps\n} from '@deck.gl/core';\n\nimport type {UnpackedIcon, IconMapping, LoadIconErrorContext} from './icon-manager';\n\ntype _IconLayerProps<DataT> = {\n data: LayerDataSource<DataT>;\n /** A prepacked image that contains all icons. */\n iconAtlas?: string | Texture;\n /** Icon names mapped to icon definitions, or a URL to load such mapping from a JSON file. */\n iconMapping?: string | IconMapping;\n\n /** Icon size multiplier.\n * @default 1\n */\n sizeScale?: number;\n /**\n * The units of the icon size, one of `meters`, `common`, and `pixels`.\n *\n * @default 'pixels'\n */\n sizeUnits?: Unit;\n /**\n * The minimum size in pixels. When using non-pixel `sizeUnits`, this prop can be used to prevent the icon from getting too small when zoomed out.\n */\n sizeMinPixels?: number;\n /**\n * The maximum size in pixels. When using non-pixel `sizeUnits`, this prop can be used to prevent the icon from getting too big when zoomed in.\n */\n sizeMaxPixels?: number;\n /** If `true`, the icon always faces camera. Otherwise the icon faces up (z)\n * @default true\n */\n billboard?: boolean;\n /**\n * Discard pixels whose opacity is below this threshold.\n * A discarded pixel would create a \"hole\" in the icon that is not considered part of the object.\n * @default 0.05\n */\n alphaCutoff?: number;\n\n /** Anchor position accessor. */\n getPosition?: Accessor<DataT, Position>;\n /** Icon definition accessor.\n * Should return the icon id if using pre-packed icons (`iconAtlas` + `iconMapping`).\n * Return an object that defines the icon if using auto-packing.\n */\n getIcon?: AccessorFunction<DataT, string> | AccessorFunction<DataT, UnpackedIcon>;\n /** Icon color accessor.\n * @default [0, 0, 0, 255]\n */\n getColor?: Accessor<DataT, Color>;\n /** Icon size accessor.\n * @default 1\n */\n getSize?: Accessor<DataT, number>;\n /** Icon rotation accessor, in degrees.\n * @default 0\n */\n getAngle?: Accessor<DataT, number>;\n /**\n * Icon offsest accessor, in pixels.\n * @default [0, 0]\n */\n getPixelOffset?: Accessor<DataT, [number, number]>;\n /**\n * Callback called if the attempt to fetch an icon returned by `getIcon` fails.\n */\n onIconError?: ((context: LoadIconErrorContext) => void) | null;\n\n /** Customize the [texture parameters](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/texParameter). */\n textureParameters?: SamplerProps | null;\n};\n\nexport type IconLayerProps<DataT = unknown> = _IconLayerProps<DataT> & LayerProps;\n\nconst DEFAULT_COLOR: [number, number, number, number] = [0, 0, 0, 255];\n\nconst defaultProps: DefaultProps<IconLayerProps> = {\n iconAtlas: {type: 'image', value: null, async: true},\n iconMapping: {type: 'object', value: {}, async: true},\n sizeScale: {type: 'number', value: 1, min: 0},\n billboard: true,\n sizeUnits: 'pixels',\n sizeMinPixels: {type: 'number', min: 0, value: 0}, // min point radius in pixels\n sizeMaxPixels: {type: 'number', min: 0, value: Number.MAX_SAFE_INTEGER}, // max point radius in pixels\n alphaCutoff: {type: 'number', value: 0.05, min: 0, max: 1},\n\n getPosition: {type: 'accessor', value: (x: any) => x.position},\n getIcon: {type: 'accessor', value: (x: any) => x.icon},\n getColor: {type: 'accessor', value: DEFAULT_COLOR},\n getSize: {type: 'accessor', value: 1},\n getAngle: {type: 'accessor', value: 0},\n getPixelOffset: {type: 'accessor', value: [0, 0]},\n\n onIconError: {type: 'function', value: null, optional: true},\n\n textureParameters: {type: 'object', ignore: true, value: null}\n};\n\n/** Render raster icons at given coordinates. */\nexport default class IconLayer<DataT = any, ExtraPropsT extends {} = {}> extends Layer<\n ExtraPropsT & Required<_IconLayerProps<DataT>>\n> {\n static defaultProps = defaultProps;\n static layerName = 'IconLayer';\n\n state!: {\n model?: Model;\n iconManager: IconManager;\n };\n\n getShaders() {\n return super.getShaders({vs, fs, modules: [project32, picking, iconUniforms]});\n }\n\n initializeState() {\n this.state = {\n iconManager: new IconManager(this.context.device, {\n onUpdate: this._onUpdate.bind(this),\n onError: this._onError.bind(this)\n })\n };\n\n const attributeManager = this.getAttributeManager();\n /* eslint-disable max-len */\n attributeManager!.addInstanced({\n instancePositions: {\n size: 3,\n type: 'float64',\n fp64: this.use64bitPositions(),\n transition: true,\n accessor: 'getPosition'\n },\n instanceSizes: {\n size: 1,\n transition: true,\n accessor: 'getSize',\n defaultValue: 1\n },\n instanceOffsets: {\n size: 2,\n accessor: 'getIcon',\n // eslint-disable-next-line @typescript-eslint/unbound-method\n transform: this.getInstanceOffset\n },\n instanceIconFrames: {\n size: 4,\n accessor: 'getIcon',\n // eslint-disable-next-line @typescript-eslint/unbound-method\n transform: this.getInstanceIconFrame\n },\n instanceColorModes: {\n size: 1,\n type: 'uint8',\n accessor: 'getIcon',\n // eslint-disable-next-line @typescript-eslint/unbound-method\n transform: this.getInstanceColorMode\n },\n instanceColors: {\n size: this.props.colorFormat.length,\n type: 'unorm8',\n transition: true,\n accessor: 'getColor',\n defaultValue: DEFAULT_COLOR\n },\n instanceAngles: {\n size: 1,\n transition: true,\n accessor: 'getAngle'\n },\n instancePixelOffset: {\n size: 2,\n transition: true,\n accessor: 'getPixelOffset'\n }\n });\n /* eslint-enable max-len */\n }\n\n /* eslint-disable max-statements, complexity */\n updateState(params: UpdateParameters<this>) {\n super.updateState(params);\n const {props, oldProps, changeFlags} = params;\n\n const attributeManager = this.getAttributeManager();\n const {iconAtlas, iconMapping, data, getIcon, textureParameters} = props;\n const {iconManager} = this.state;\n\n if (typeof iconAtlas === 'string') {\n return;\n }\n\n // internalState is always defined during updateState\n const prePacked = iconAtlas || this.internalState!.isAsyncPropLoading('iconAtlas');\n iconManager.setProps({\n loadOptions: props.loadOptions,\n autoPacking: !prePacked,\n iconAtlas,\n iconMapping: prePacked ? (iconMapping as IconMapping) : null,\n textureParameters\n });\n\n // prepacked iconAtlas from user\n if (prePacked) {\n if (oldProps.iconMapping !== props.iconMapping) {\n attributeManager!.invalidate('getIcon');\n }\n } else if (\n changeFlags.dataChanged ||\n (changeFlags.updateTriggersChanged &&\n (changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getIcon))\n ) {\n // Auto packing - getIcon is expected to return an object\n iconManager.packIcons(data, getIcon as AccessorFunction<any, UnpackedIcon>);\n }\n\n if (changeFlags.extensionsChanged) {\n this.state.model?.destroy();\n this.state.model = this._getModel();\n attributeManager!.invalidateAll();\n }\n }\n /* eslint-enable max-statements, complexity */\n\n get isLoaded(): boolean {\n return super.isLoaded && this.state.iconManager.isLoaded;\n }\n\n finalizeState(context: LayerContext): void {\n super.finalizeState(context);\n // Release resources held by the icon manager\n this.state.iconManager.finalize();\n }\n\n draw({uniforms}): void {\n const {sizeScale, sizeMinPixels, sizeMaxPixels, sizeUnits, billboard, alphaCutoff} = this.props;\n const {iconManager} = this.state;\n\n const iconsTexture = iconManager.getTexture();\n if (iconsTexture) {\n const model = this.state.model!;\n const iconProps: IconProps = {\n iconsTexture,\n iconsTextureDim: [iconsTexture.width, iconsTexture.height],\n sizeUnits: UNIT[sizeUnit