Map Blocks
Interactive MapLibre maps — analytics overview, logistics network, geographic heatmap and live delivery tracking.
Preview
@props([
'heading' => 'Seismic activity',
'subheading' => 'Earthquake density, last 30 days',
// [longitude, latitude] the globe is initially centred on.
'center' => [150, 0],
'zoom' => 1.3,
// Low → high density colour ramp as TOKEN NAMES (resolved to themed colours
// at runtime — never raw hex). The map renders the heatmap from these.
'ramp' => ['info', 'primary', 'warning', 'destructive'],
// Optional override: a GeoJSON FeatureCollection (PHP array) of Point
// features, each with a numeric properties.mag weight. Defaults below.
'quakes' => null,
])
@php
// Authored (non-random) sample of recent quakes scattered around the Pacific
// "Ring of Fire": Japan, Indonesia/Philippines, the Andes, Alaska, the US
// West Coast and New Zealand. Each [lng, lat, mag].
$points = $quakes ?? [
// Japan / Kuril arc
[142.4, 38.3, 6.8], [141.0, 37.1, 4.2], [143.9, 41.6, 5.1], [140.2, 35.7, 3.4],
[138.5, 34.9, 2.6], [144.7, 43.2, 4.9], [131.6, 33.2, 3.1],
// Philippines / Indonesia
[125.4, 7.1, 6.2], [122.8, 0.9, 5.4], [119.7, -3.6, 4.7], [127.3, 1.5, 3.8],
[112.9, -8.2, 5.9], [106.4, -6.9, 2.9], [130.1, -3.4, 4.1], [124.0, 12.7, 3.6],
// New Zealand / Tonga
[174.8, -41.3, 5.7], [176.2, -38.6, 4.4], [-175.2, -20.1, 6.4], [178.0, -37.4, 3.2],
// Alaska / Aleutians
[-150.6, 61.2, 6.1], [-153.4, 59.8, 4.6], [-162.3, 54.7, 5.3], [-147.9, 63.1, 2.8],
// US West Coast
[-122.3, 37.8, 4.0], [-118.4, 34.1, 3.5], [-124.2, 40.6, 5.0], [-121.9, 36.6, 2.4],
[-116.9, 33.4, 3.7],
// Mexico / Central America
[-99.1, 16.8, 5.6], [-104.7, 19.2, 4.3], [-91.3, 14.1, 3.9],
// Andes (Peru, Chile)
[-71.6, -33.0, 6.6], [-70.4, -23.7, 5.2], [-72.9, -38.1, 4.8], [-77.0, -12.0, 3.3],
[-69.8, -18.5, 5.5], [-73.2, -45.4, 4.1],
// Caribbean / Cascadia tail
[-61.0, 14.6, 3.0], [-126.7, 47.5, 4.5], [155.2, -6.3, 6.0], [167.1, -15.4, 4.2],
];
// Build an inline GeoJSON FeatureCollection from the authored list.
$features = [];
foreach ($points as [$lng, $lat, $mag]) {
$features[] = [
'type' => 'Feature',
'properties' => ['mag' => $mag],
'geometry' => ['type' => 'Point', 'coordinates' => [$lng, $lat]],
];
}
$geojson = ['type' => 'FeatureCollection', 'features' => $features];
$count = count($features);
// Legend swatches: token bg classes, low → high density.
$legend = [
['class' => 'bg-info', 'label' => __('Low')],
['class' => 'bg-primary', 'label' => __('Moderate')],
['class' => 'bg-warning', 'label' => __('High')],
['class' => 'bg-destructive', 'label' => __('Severe')],
];
@endphp
<x-ui.card {{ $attributes->merge(['class' => 'w-full']) }}>
<x-ui.card.header>
<div class="flex flex-wrap items-start justify-between gap-4">
<div class="space-y-2">
<x-ui.card.title>{{ __($heading) }}</x-ui.card.title>
<x-ui.card.description>{{ __($subheading) }}</x-ui.card.description>
</div>
<x-ui.badge variant="secondary" class="tabular-nums">
{{ trans_choice('{1} :count event|[2,*] :count events', $count, ['count' => number_format($count)]) }}
</x-ui.badge>
</div>
</x-ui.card.header>
<x-ui.card.content class="space-y-4">
<x-ui.map
projection="globe"
:center="$center"
:zoom="$zoom"
height="520px"
:label="__('Earthquake density heatmap')"
:heatmap="[
'data' => $geojson,
'weight' => 'mag',
'intensity' => 1,
'radius' => 30,
'colors' => $ramp,
]"
>
<x-ui.map.controls position="top-right" show-zoom />
</x-ui.map>
<x-ui.separator />
{{-- Density legend: low → high using token swatch chips. --}}
<div class="flex flex-wrap items-center gap-x-4 gap-y-2">
<span class="text-xs font-medium text-muted-foreground">{{ __('Low') }}</span>
<ul class="flex flex-wrap items-center gap-4">
@foreach ($legend as $step)
<li class="flex items-center gap-2 text-xs text-muted-foreground">
<span class="size-3 shrink-0 rounded-full {{ $step['class'] }}" aria-hidden="true"></span>
{{ $step['label'] }}
</li>
@endforeach
</ul>
<span class="text-xs font-medium text-muted-foreground">{{ __('High') }}</span>
</div>
</x-ui.card.content>
</x-ui.card>
Installation
php artisan ui:add blocks/maps-heatmap
Registry contract
Install confidence
php artisan ui:add blocks/maps-heatmap
writes only the generated targets below. The CLI validates each file hash before writing and
prompts before replacing local changes unless --force is used.
- Version
- 1.0.4
- License
- open
- Stability
- stable
- Contract
- v1
- Foundation
- ≥ 1.0.0
| Type | Generated target |
|---|---|
| blade | resources/views/blocks/maps-heatmap.blade.php |
Registry dependencies
Package dependencies
composer: jml/brok:^0.2
npm: maplibre-gl
Use with AI
A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.
# Brok UI block: Map Heatmap (`maps-heatmap`)
Geographic density heatmap of seismic activity around the Pacific Ring of Fire.
Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.
## Install
```bash
php artisan ui:add blocks/maps-heatmap
```
## Render it
```blade
<x-blocks.maps-heatmap />
```
## Props
- `heading` (string, default `Seismic activity`) — Card title.
- `subheading` (string, default `Earthquake density, last 30 days`) — Supporting copy under the heading.
- `center` (array, default `[150, 0]`) — [longitude, latitude] the globe is initially centred on.
- `zoom` (float, default `1.3`) — Initial zoom level.
- `ramp` (array, default `['info', 'primary', 'warning', 'destructive']`) — Low-to-high heatmap colour ramp as token names, never raw hex.
- `quakes` (mixed|null, default `null`) — Optional GeoJSON FeatureCollection of Point features with a numeric properties.mag weight; null uses a sample Ring-of-Fire dataset.
## Use when
- Visualising geographic point-density data, such as seismic events, as a heatmap layer on a rotating globe.
- Showing a low-to-high legend alongside an event-count badge instead of discrete markers.
## Avoid when
- Needing discrete hub or courier markers with popups instead of a diffuse density layer; use maps-analytics, maps-logistics, or maps-delivery-tracker.
## Rules
- Render the installed block with `<x-blocks.maps-heatmap />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.
## Links
- Docs: https://brokui.dev/blocks/maps-heatmap
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/maps-heatmap.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
Guidance
Use when
- Visualising geographic point-density data, such as seismic events, as a heatmap layer on a rotating globe.
- Showing a low-to-high legend alongside an event-count badge instead of discrete markers.
Avoid when
- Needing discrete hub or courier markers with popups instead of a diffuse density layer; use maps-analytics, maps-logistics, or maps-delivery-tracker.
Anti-patterns
- Do not replace semantic props with conflicting utility classes.
- Do not remove labels, focus styles, or state attributes.
- Anatomy
Usage
Render the block as a component, passing data where useful:
<x-blocks.maps-heatmap />
Built from primitives
This block composes installed <brok:*> primitives and semantic design
tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by
editing CSS variables; flip the preview to RTL to confirm it mirrors.
Source
The exact, editable file ui:add writes
into your app. The preview above renders this same source — there are no preview-only blocks.
@props([
'heading' => 'Seismic activity',
'subheading' => 'Earthquake density, last 30 days',
// [longitude, latitude] the globe is initially centred on.
'center' => [150, 0],
'zoom' => 1.3,
// Low → high density colour ramp as TOKEN NAMES (resolved to themed colours
// at runtime — never raw hex). The map renders the heatmap from these.
'ramp' => ['info', 'primary', 'warning', 'destructive'],
// Optional override: a GeoJSON FeatureCollection (PHP array) of Point
// features, each with a numeric properties.mag weight. Defaults below.
'quakes' => null,
])
@php
// Authored (non-random) sample of recent quakes scattered around the Pacific
// "Ring of Fire": Japan, Indonesia/Philippines, the Andes, Alaska, the US
// West Coast and New Zealand. Each [lng, lat, mag].
$points = $quakes ?? [
// Japan / Kuril arc
[142.4, 38.3, 6.8], [141.0, 37.1, 4.2], [143.9, 41.6, 5.1], [140.2, 35.7, 3.4],
[138.5, 34.9, 2.6], [144.7, 43.2, 4.9], [131.6, 33.2, 3.1],
// Philippines / Indonesia
[125.4, 7.1, 6.2], [122.8, 0.9, 5.4], [119.7, -3.6, 4.7], [127.3, 1.5, 3.8],
[112.9, -8.2, 5.9], [106.4, -6.9, 2.9], [130.1, -3.4, 4.1], [124.0, 12.7, 3.6],
// New Zealand / Tonga
[174.8, -41.3, 5.7], [176.2, -38.6, 4.4], [-175.2, -20.1, 6.4], [178.0, -37.4, 3.2],
// Alaska / Aleutians
[-150.6, 61.2, 6.1], [-153.4, 59.8, 4.6], [-162.3, 54.7, 5.3], [-147.9, 63.1, 2.8],
// US West Coast
[-122.3, 37.8, 4.0], [-118.4, 34.1, 3.5], [-124.2, 40.6, 5.0], [-121.9, 36.6, 2.4],
[-116.9, 33.4, 3.7],
// Mexico / Central America
[-99.1, 16.8, 5.6], [-104.7, 19.2, 4.3], [-91.3, 14.1, 3.9],
// Andes (Peru, Chile)
[-71.6, -33.0, 6.6], [-70.4, -23.7, 5.2], [-72.9, -38.1, 4.8], [-77.0, -12.0, 3.3],
[-69.8, -18.5, 5.5], [-73.2, -45.4, 4.1],
// Caribbean / Cascadia tail
[-61.0, 14.6, 3.0], [-126.7, 47.5, 4.5], [155.2, -6.3, 6.0], [167.1, -15.4, 4.2],
];
// Build an inline GeoJSON FeatureCollection from the authored list.
$features = [];
foreach ($points as [$lng, $lat, $mag]) {
$features[] = [
'type' => 'Feature',
'properties' => ['mag' => $mag],
'geometry' => ['type' => 'Point', 'coordinates' => [$lng, $lat]],
];
}
$geojson = ['type' => 'FeatureCollection', 'features' => $features];
$count = count($features);
// Legend swatches: token bg classes, low → high density.
$legend = [
['class' => 'bg-info', 'label' => __('Low')],
['class' => 'bg-primary', 'label' => __('Moderate')],
['class' => 'bg-warning', 'label' => __('High')],
['class' => 'bg-destructive', 'label' => __('Severe')],
];
@endphp
<x-ui.card {{ $attributes->merge(['class' => 'w-full']) }}>
<x-ui.card.header>
<div class="flex flex-wrap items-start justify-between gap-4">
<div class="space-y-2">
<x-ui.card.title>{{ __($heading) }}</x-ui.card.title>
<x-ui.card.description>{{ __($subheading) }}</x-ui.card.description>
</div>
<x-ui.badge variant="secondary" class="tabular-nums">
{{ trans_choice('{1} :count event|[2,*] :count events', $count, ['count' => number_format($count)]) }}
</x-ui.badge>
</div>
</x-ui.card.header>
<x-ui.card.content class="space-y-4">
<x-ui.map
projection="globe"
:center="$center"
:zoom="$zoom"
height="520px"
:label="__('Earthquake density heatmap')"
:heatmap="[
'data' => $geojson,
'weight' => 'mag',
'intensity' => 1,
'radius' => 30,
'colors' => $ramp,
]"
>
<x-ui.map.controls position="top-right" show-zoom />
</x-ui.map>
<x-ui.separator />
{{-- Density legend: low → high using token swatch chips. --}}
<div class="flex flex-wrap items-center gap-x-4 gap-y-2">
<span class="text-xs font-medium text-muted-foreground">{{ __('Low') }}</span>
<ul class="flex flex-wrap items-center gap-4">
@foreach ($legend as $step)
<li class="flex items-center gap-2 text-xs text-muted-foreground">
<span class="size-3 shrink-0 rounded-full {{ $step['class'] }}" aria-hidden="true"></span>
{{ $step['label'] }}
</li>
@endforeach
</ul>
<span class="text-xs font-medium text-muted-foreground">{{ __('High') }}</span>
</div>
</x-ui.card.content>
</x-ui.card>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.4 - Status
- Stable
- License
-
open - Deprecation
- Not deprecated
- Contract
-
v1 - Foundation
-
≥ 1.0.0