Volcano

Getting Started

Choose the Compose or React integration and render a first heatmap.

For a React web app, install @taewooyo/heatmap-react with npm and follow React Integration. The Gradle instructions below apply to Android, iOS, and Desktop Compose apps, not React consumers.

Install for Compose Multiplatform

Add the core and Compose artifacts to commonMain. volcano owns the platform-neutral model and layout transforms; volcano-compose renders that model with Compose Multiplatform.

Use Kotlin/Compose 2.0.3 for core, Compose, and optional Coil. This version preserves valid navigation across data refreshes and adds source lookup for aggregated items plus accessibility improvements.
kotlin {
  sourceSets { commonMain.dependencies {
    implementation("io.github.taewooyo:volcano:2.0.3")
    implementation("io.github.taewooyo:volcano-compose:2.0.3")
  } }
}

Use the same dependencies whether the consuming application targets Android, iOS, Desktop, or all three. Add volcano-compose-coil only when remote imageUrl values should be loaded with Coil. The base UI module does not fetch images.

Build valid source data

Every node needs a non-blank sibling-unique id, a display label, and a finite value. A positive value receives area; zero and negative values have no visual area. A group derives its layout weight from visible descendants when they have positive values.

metric is optional and independent from area. It is normally a signed change, error-rate delta, or health score. imageUrl is optional; null and blank values intentionally request no logo.

Render a heatmap

val market = HeatmapNode(
  id = "market",
  label = "Market",
  value = 100.0,
  children = listOf(
    HeatmapNode(id = "nvidia", label = "NVIDIA", value = 100.0, metric = 2.3),
  ),
)

val state = rememberHeatmapState(market)
Heatmap(state = state, modifier = Modifier.fillMaxSize())

The Heatmap deliberately has no fixed size. The host owns constraints, so specify a useful height or let a parent provide bounded height.

Heatmap(
  state = state,
  modifier = Modifier.fillMaxWidth().height(320.dp),
)

value controls area. metric controls the default signed color scale. Continue with Platform Integration before wiring a real application.

On this page