FeatureEvaluator
FeatureEvaluator is a class that provides access to feature data and dynamic styling of features based on their properties. It can be obtained through the featureCreated and featureUpdated events of a Layer.
This class allows you to:
- Read feature properties from data sources
- Dynamically style features based on their properties
Properties
Section titled “Properties”Type: FeatureSetId
Description: Gets the unique identifier of this feature set.
Example:
layer.on("featureCreated", ({ evaluator }) => { console.log("Feature ID:", evaluator.id);});FeatureInfo
Section titled “FeatureInfo”type FeatureInfo = { batchId: number; properties: Record<string, unknown> | undefined; layerId: string | undefined;};FeatureEvaluatorCallback
Section titled “FeatureEvaluatorCallback”type FeatureEvaluatorCallback = ( info: FeatureInfo,) => Partial<EvaluatedValue>;Methods
Section titled “Methods”readFeatureProperties()
Section titled “readFeatureProperties()”Reads the properties of this feature from the data source. The callback is invoked for each batch within this feature.
Syntax:
readFeatureProperties( f: (info: FeatureInfo) => void): voidParameters:
f: A callback function that receives a FeatureInfo object for each batch
Example:
// Log all propertiesevaluator.readFeatureProperties(({ batchId, properties }) => { console.log(`Batch ${batchId}:`, properties);});
evaluator.readFeatureProperties(({ properties }) => { const attributes = properties?.["attributes"] ?? {}; const minHeight = attributes["minHeight"]; const maxHeight = attributes["maxHeight"]; console.log("Height range:", minHeight, "-", maxHeight);});readFilteredFeatureProperties()
Section titled “readFilteredFeatureProperties()”Reads only the specified root property keys of this feature from the data source. More efficient than readFeatureProperties() when only a few properties are needed.
Syntax:
readFilteredFeatureProperties( keys: string[], f: (info: FeatureInfo) => void): voidParameters:
keys: An array of root property keys to readf: A callback function that receives a FeatureInfo object with only the filtered properties
Example:
evaluator.readFilteredFeatureProperties(["height", "name"], ({ batchId, properties }) => { console.log(`Batch ${batchId}: height=${properties?.["height"]}, name=${properties?.["name"]}`);});evaluate()
Section titled “evaluate()”Evaluates and applies dynamic styles to features based on their properties. The callback is invoked for each batch (sub-feature) within this feature.
Syntax:
evaluate( f: FeatureEvaluatorCallback, options?: { filters?: string[]; }): voidParameters:
f: A callback function that receives a FeatureInfo object and returns style valuesoptions: Optional configurationoptions.filters: An array of root property keys to read. When specified, only the matched properties are passed to the callback, improving performance for large datasets.
Returns:
The callback function can return an object containing the following properties:
| Property | Type | Description |
|---|---|---|
color | Color | Feature color (using new Color()) |
show | boolean | Feature visibility (show/hide) |
height | number | Feature height (meters) |
extrudedHeight | number | Polygon extrusion height (meters) |
text | string | Label text content (for text/label features) |
width | number | Line width (pixels, for polyline features) |
size | number | Point/text size (meters or pixels, for point/text features) |
opacity | number | Feature opacity, range 0.0-1.0 (for polygons/points/billboards/models/text) |
declutterPriority | number | Placement priority for decluttering; higher wins an overlap (for points/billboards/text with declutter enabled). Overrides the layer’s declutterPriority |
image | string | null | Image URL (for billboard features); each distinct URL is loaded once and packed into the layer’s texture atlas. Return null to clear a previous per-feature image and revert to the billboard material’s default url |
Example:
import { Color } from "@navaramap/three";
// Color 3D Tiles buildings by heightlayer.on("featureUpdated", ({ evaluator }) => { evaluator.evaluate(({ properties }) => { const measuredHeight = properties?.["height"] as number;
const color = (() => { if (measuredHeight < 30) return new Color().setStyle("#00ff00"); if (measuredHeight < 60) return new Color().setStyle("#ffff00"); if (measuredHeight < 90) return new Color().setStyle("#ff00ff"); return new Color().setStyle("#ff0000"); })();
return { color, show: measuredHeight >= 30, // Hide low buildings }; });});// Apply property-based extrusion to GeoJSON polygonslayer.on("featureUpdated", ({ evaluator }) => { evaluator.evaluate(({ properties }) => { const height = (properties?.["height"] as number) ?? 0; const extrudedHeight = (properties?.["extrudedHeight"] as number) ?? 0;
return { height, extrudedHeight, }; });});// Color MVT features by category propertylayer.on("featureUpdated", ({ evaluator }) => { evaluator.evaluate(({ properties }) => { const category = properties?.["category"] as string;
const color = (() => { if (category === "A") return "#0000ff"; if (category === "B") return "#00ff00"; return "#ff0000"; })();
return { color: new Color().setStyle(color), }; });});// Filter and style text labelslayer.on("featureUpdated", ({ evaluator }) => { evaluator.evaluate(({ properties }) => { const text = properties?.["name"] as string;
return { text, show: !!text, }; });});// Set per-feature billboard images based on a propertylayer.on("featureUpdated", ({ evaluator }) => { evaluator.evaluate( ({ properties }) => { const icon = properties?.["icon"] as string | undefined; // Features without an icon fall back to the billboard material's // default url; `image: null` also clears a previously set image return { image: icon ? `/icons/${icon}.svg` : null }; }, { filters: ["icon"] }, );});// Rank city labels above village labels when declutteringconst TIER_PRIORITY: Record<number, number> = { 1: 3, 2: 2, 3: 1 };
layer.on("featureUpdated", ({ evaluator }) => { evaluator.evaluate(({ properties }) => ({ text: properties?.["name"] as string, declutterPriority: TIER_PRIORITY[properties?.["tier"] as number] ?? 0, }));});// Highlight selected feature with pick eventlet selectedId: string | undefined;
// Select feature on clickview.on("pick", (info) => { selectedId = info?.properties?.["id"] as string; layer.forceUpdate(); // Re-evaluate styles});
// Change color based on selection statelayer.on("featureUpdated", ({ evaluator }) => { evaluator.evaluate(({ properties }) => { const id = properties?.["id"] as string;
return { color: new Color().setHex(selectedId === id ? 0xff0000 : 0xffffff), }; });});EvaluatedValue Type
Section titled “EvaluatedValue Type”Type definition that can be returned from the evaluate() callback:
type EvaluatedValue = { /** Feature color */ color?: Color; /** Feature visibility (show/hide) */ show?: boolean; /** Polygon extrusion height (meters) */ extrudedHeight?: number; /** Feature height (meters) */ height?: number; /** Label text content */ text?: string; /** Line width (pixels, for polyline features) */ width?: number; /** Point/text size (meters or pixels, for point/text features) */ size?: number; /** Feature opacity, range 0.0-1.0 (for polygons/points/billboards/models/text) */ opacity?: number; /** Placement priority for decluttering; higher wins an overlap (for * points/billboards/text with `declutter` enabled). Overrides the * layer's `declutterPriority` */ declutterPriority?: number; /** Image URL (for billboard features); each distinct URL is loaded once and * packed into the layer's texture atlas. `null` clears a previous * per-feature image, reverting to the billboard material's default url */ image?: string | null;};