## Visualize KML placemarks

A KML placemark is a feature with associated geometry. LuciadRIA represents it as `KMLPlacemarkFeature`. Visualizing KML data with KML placemarks on a map requires two steps:

1. Create a `KMLModel` by loading a KML file.

2. Use a `KMLLayer` to visualize the model.

``````//First decode the data into a model
const model = new KMLModel(url);

//Create a layer for the model
//The layer visualizes the KML data using the
//styling information provided in the data
const layer = new KMLLayer(model);

//Add the layer to the map

You can also use a `KMLCodec` with any kind of `Store`. For example, you can use a `WFSFeatureStore` to connect to a WFS service returning KML data, or you can implement a custom `Store` that decodes KML data from a string.

The example shows how to visualize KML data using a custom `Store` that reads KML data directly from a string.
``````//StringStore is a read only store that can handle KML data from a string
class StringStore implements Store {

constructor(kmlString: string) {
this.content = kmlString;
this.codec = new KMLCodec();
}

query(_query?: object, _options?: object): Cursor | Promise<Cursor> {
return this.codec.decode({content: this.content});
}
}

//Instantiate the StringStore and configure a FeatureModel with it.
//Where the kmlString contains a text with KML data
const store = new StringStore(kmlString);
const model = new FeatureModel(store);

//Create a layer for the model
const layer = new KMLLayer(model as KMLModel);

//Add the layer to the map

A KML network link is a feature that references a KML or KMZ file on a local or remote network. LuciadRIA represents a KML network link as `KMLNetworkLinkFeature`. When the `KMLCodec` encounters a KML network link while it’s decoding KML data, it emits a `"KMLNetworkLink"` event with the `KMLNetworkLinkFeature` instance. For your convenience, the `KMLModel` propagates this event from the `KMLCodec`. You can register a handler function that consumes this event to create a new `KMLLayer` for the emitted `KMLNetworkLinkFeature`.

 You don’t get instances of `KMLNetworkLinkFeature` when you iterate over a `Cursor` returned by `KMLCodec.decode()`.

## Handle KML ground overlays

A KML ground overlay represents an image overlay draped onto the terrain. Both the `KMLCodec` and the `KMLModel` emit the `"KMLGroundOverlay"` event with a `KMLGroundOverlayFeature`. You can register a handler function that consumes this event to create a new `RasterTileSetLayer` for the emitted `KMLGroundOverlayFeature`.

 You don’t get instances of `KMLGroundOverlayFeature` when you iterate over a `Cursor` returned by `KMLCodec.decode()`.

### Example of how to handle "KMLNetworkLink" and "KMLGroundOverlay" events

The example shows how to handle the `"KMLNetworkLink"` and `"KMLGroundOverlay"` events.
``````//Register handlers for KML events

(layer.model as KMLModel)?.on("KMLGroundOverlay",
(groundOverlay: KMLGroundOverlayFeature) => onKMLGroundOverlayEvent(groundOverlay, layer));
}

//Create a new KML layer that points to the network link's KML data
id: `${id}`, label: `${name}`
});
//Register handlers for newly created KML layer
//Add the layer to the map
}
}

//Handler to consume KMLGroundOverlay event
function onKMLGroundOverlayEvent(groundOverlay: KMLGroundOverlayFeature, parentLayer: KMLLayer) {
const {id, properties, shape} = groundOverlay;
const {icon, name} = properties;

if (shape && shape.bounds && icon && icon.href) {
//Create a new raster layer with the referenced image
const model = new UrlTileSetModel({
reference: getReference("CRS:84"),
bounds: shape?.bounds,
baseURL: icon.href,
levelCount: 1
});
const rasterLayer = new RasterTileSetLayer(model, {
id: `${id}`, label: `${name}`
});

//Add the layer to the map
}
}``````

## Handle the KML data structure

KML data holds features nested in KML containers: KML document and KML folder. LuciadRIA represents those as `KMLDocumentContainer` and `KMLFolderContainer`. Both `KMLDocumentContainer` and `KMLFolderContainer` expose the `children` property with a value that’s an ordered array of all discovered KML features of the types `KMLFolderContainer`, `KMLPlacemarkFeature`, but also the types `KMLNetworkLinkFeature` and `MLGroundOverlayFeature`.

When the `KMLCodec` has fully decoded the KML data, it emits a single `"KMLTree"` event with the top-most KML container element. Usually, that’s a `KMLDocumentContainer`. You can register a handler for the `"KMLTree"` event on the `KMLCodec` or `KMLModel` to build a user interface that reflects the hierarchical data structure.

Each `KMLFeature` has common `properties` that you can use for setting the initial states of UI components, for example:

• `open` - specifies whether to show an expanded or collapsed Document or Folder.

• `visibility` - specifies whether to make a feature visible or not when it’s first loaded.

• `snippet` - a short description of the feature.

The example shows how to handle the `"KMLTree"` event to count specific features.
``````// Count all features in folders that contain the "Buildings" text in the "name" property
(kmlLayer.model as KMLModel)?.on("KMLTree", (treeData: KMLFeature[]) => {
const count = treeData.reduce((result: number, feature: KMLFeature) => {
return (feature instanceof KMLFolderContainer &&
feature.properties.name &&
feature.properties.name.indexOf("Buildings") > -1) ?
result + feature.children.length :
result
}, 0);
console.log("Number of features in 'Buildings' folders", count);
});``````
 See the `KML` sample to find out how to create a UI component which displays the data structure of loaded KML.