Skip to main content
The Feature Style Extension (nga_feature_style) is an NGA community extension that stores visual rendering hints inside a GeoPackage. Styles and icons are stored in dedicated attribute tables and linked to feature rows via the Related Tables Extension, so any client that reads them can render features consistently without external style sheets.
This is an NGA community extension. It builds on top of the Related Tables Extension and the Contents ID extension.

Architecture

The extension maintains four relationship types per feature table:
RelationshipPurpose
StyleRow-level stroke styles (color, opacity, width)
Table StyleDefault stroke style for the entire table
IconRow-level point icon images
Table IconDefault icon image for the entire table
Styles are rows in a StyleTable (an attributes table). Icons are rows in an IconTable (a media table). Mapping tables join feature row IDs to style/icon row IDs.

Key Classes

FeatureStyleExtension

Low-level extension class. Creates and queries style and icon relationships. High-level facade scoped to a single feature table. Manages all four relationship types and caches the table-level defaults.
import { FeatureTableStyles } from '@ngageoint/geopackage';

const tableStyles = new FeatureTableStyles(geoPackage, 'my_features');

StyleRow Properties

A StyleRow represents a single stroke/fill style definition.
name
string
Human-readable label for this style.
description
string
Optional description.
color
string
Hex color string for the stroke (e.g. #FF0000). Use setHexColor() / getHexColor().
opacity
number
Stroke opacity from 0.0 (transparent) to 1.0 (opaque). Defaults to 1.0.
fillColor
string
Hex color for polygon fill. Use setFillHexColor() / getFillHexColor().
fillOpacity
number
Fill opacity from 0.0 to 1.0. Defaults to 1.0.
width
number
Stroke width in pixels. Must be >= 0.0.

IconRow Properties

An IconRow is a media row that stores a raster icon image for point features.
name
string
Human-readable label.
data
Buffer
Raw image bytes. Use setData() / getData().
contentType
string
MIME type of the image (e.g. image/png). Use setContentType() / getContentType().
width
number
Display width of the icon in pixels.
height
number
Display height of the icon in pixels.
anchorU
number
Horizontal anchor point from 0.0 (left) to 1.0 (right). Default 0.5 (center).
anchorV
number
Vertical anchor point from 0.0 (top) to 1.0 (bottom). Default 1.0 (bottom, typical map pin).

Setting Up Styles

1

Initialize the extension for a feature table

import { FeatureTableStyles, StyleRow, IconRow } from '@ngageoint/geopackage';

const tableStyles = new FeatureTableStyles(geoPackage, 'my_features');

// Create all four relationship tables at once
tableStyles.createRelationships();
2

Create a default table-level style

// Get the style DAO
const styleDao = tableStyles.getFeatureStyleExtension().getStyleDao();

const defaultStyle = styleDao.newRow();
defaultStyle.setName('Default Line');
defaultStyle.setHexColor('#0077CC');
defaultStyle.setOpacity(1.0);
defaultStyle.setWidth(2.0);

// Assign as the default style for the entire table
tableStyles.setTableStyle(null, defaultStyle); // null = all geometry types
3

Assign a row-level style to a specific feature

const highlightStyle = styleDao.newRow();
highlightStyle.setName('Highlight');
highlightStyle.setHexColor('#FF4500');
highlightStyle.setOpacity(0.9);
highlightStyle.setWidth(4.0);

// Assign to feature row ID 42
const featureDao = geoPackage.getFeatureDao('my_features');
const featureRow = featureDao.queryForId(42);
tableStyles.setStyle(featureRow, null, highlightStyle);

Setting Up Icons

import * as fs from 'fs';

const iconDao = tableStyles.getFeatureStyleExtension().getIconDao();

// Create a table-level default icon
const icon = iconDao.newRow();
icon.setName('Blue Pin');
icon.setData(fs.readFileSync('pin.png'));
icon.setContentType('image/png');
icon.setWidth(24);
icon.setHeight(24);
icon.setAnchorU(0.5);  // horizontally centered
icon.setAnchorV(1.0);  // anchored at the bottom

tableStyles.setTableIcon(null, icon); // null = all geometry types

Getting Styles for Rendering

When rendering features, retrieve the effective style or icon (row-level overrides table-level defaults):
const featureRow = featureDao.queryForId(42);

// Get the effective style (row-level preferred, falls back to table default)
const featureStyle = tableStyles.getFeatureStyle(featureRow);

if (featureStyle !== null) {
  const style = featureStyle.getStyle();
  const icon  = featureStyle.getIcon();

  if (style !== null) {
    const color   = style.getHexColor();     // '#0077CC'
    const opacity = style.getOpacityOrDefault();  // 1.0
    const width   = style.getWidthOrDefault();    // 2.0
    const fill    = style.getFillHexColor(); // null if not set
  }

  if (icon !== null) {
    const imageData = icon.getData();
    const mime      = icon.getContentType();
  }
}

Geometry-Type-Specific Styles

Styles can be assigned per geometry type using the GeometryType enum:
import { GeometryType } from '@ngageoint/simple-features-js';

// Assign a polygon-specific fill style
const fillStyle = styleDao.newRow();
fillStyle.setHexColor('#228B22');
fillStyle.setFillHexColor('#90EE90');
fillStyle.setFillOpacity(0.5);

tableStyles.setTableStyle(GeometryType.POLYGON, fillStyle);

// Retrieve the polygon-specific style for a row
const style = tableStyles.getStyle(featureRow, GeometryType.POLYGON);

Checking Extension Status

// Is the extension registered for this table?
const hasExtension = tableStyles.has();

// Are any style/icon relationships set up?
const hasRelationship = tableStyles.hasRelationship();

// Individual relationship checks
const hasStyles      = tableStyles.hasStyleRelationship();
const hasTableStyles = tableStyles.hasTableStyleRelationship();
const hasIcons       = tableStyles.hasIconRelationship();
const hasTableIcons  = tableStyles.hasTableIconRelationship();

Build docs developers (and LLMs) love