@giro3d/giro3d
Version:
A JS/WebGL framework for 3D geospatial data visualization
113 lines (94 loc) • 3.01 kB
text/typescript
/*
* Copyright (c) 2015-2018, IGN France.
* Copyright (c) 2018-2026, Giro3D team.
* SPDX-License-Identifier: MIT
*/
import { type Feature } from 'ol';
import { type Geometry } from 'ol/geom';
import { Texture, UnsignedByteType, type TextureDataType } from 'three';
import type { LayerOptions, LayerUserData, Target } from './Layer';
import OffsetScale from '../OffsetScale';
import ColorLayer from './ColorLayer';
/**
* Modes of the mask layer.
*/
export enum MaskMode {
/**
* The mask is applied normally: transparents parts of the mask make the map transparent.
*/
Normal = 1,
/**
* The mask is inverted: transparents parts of the mask make the map opaque.
*/
Inverted = 2,
}
const EMPTY_TEXTURE = new Texture();
const DEFAULT_PITCH = OffsetScale.identity();
export interface MaskLayerOptions extends LayerOptions {
/**
* How to interpret the mask.
*/
maskMode?: MaskMode;
}
/**
* A {@link ColorLayer} that can be used to mask parts of
* a map. The source can be any source supported by the color layers.
*
*/
export class MaskLayer<
UserData extends LayerUserData = LayerUserData,
> extends ColorLayer<UserData> {
private _maskMode: MaskMode;
/**
* Read-only flag to check if a given object is of type MaskLayer.
*/
public readonly isMaskLayer: boolean = true;
/**
* Creates a mask layer.
* It should be added in a `Map` to be displayed in the instance.
* See the example for more information on layer creation.
*
* @param options - The layer options.
*/
public constructor(options: MaskLayerOptions) {
super(options);
this.isMaskLayer = true;
this.type = 'MaskLayer';
this._maskMode = options.maskMode ?? MaskMode.Normal;
}
/**
* Gets or set the mask mode.
*/
public get maskMode(): MaskMode {
return this._maskMode;
}
public set maskMode(v: MaskMode) {
this._maskMode = v;
}
public override getRenderTargetDataType(): TextureDataType {
return UnsignedByteType;
}
public override applyEmptyTextureToNode(target: Target): void {
const material = target.node.material;
if (!material.hasColorLayer(this)) {
material.pushColorLayer(this, target.extent);
}
// We cannot remove the layer from the material, contrary to what is done for
// other layer types, because since this layer acts as a mask, it must be defined
// for the entire map.
material.setColorTextures(this, {
texture: EMPTY_TEXTURE,
pitch: DEFAULT_PITCH,
});
}
public override getVectorFeaturesAtCoordinate(): Feature<Geometry>[] {
return [];
}
public override getVectorFeaturesInExtent(): Feature<Geometry>[] {
return [];
}
}
export function isMaskLayer(obj: unknown): obj is MaskLayer {
return (obj as MaskLayer)?.isMaskLayer;
}
export default MaskLayer;