Leaflet Heatmap Density Layer — Free HTML CSS JS Snippet

Leaflet Heatmap Density Layer · Charts · Plain HTML, CSS & JS · Live preview

What's included

Features

Weighted intensity points
Each point contributes its own weight, not just its count.
Live-adjustable radius and blur
setOptions re-renders without rebuilding point data.
Raw-points verification overlay
A toggle to check the heatmap against real point density.
Efficient layer-group toggling
Hundreds of points added/removed as one unit.
Realistic clustered sample data
Points cluster around real hotspots, not uniform noise.
Free OpenStreetMap tiles
No API key or paid map provider required.

About this UI Snippet

Leaflet Heatmap Density Layer — Weighted Points, Not Just Counted Ones

Screenshot of the Leaflet Heatmap Density Layer snippet rendered live

A density heatmap is more informative than a cluster of markers when the question is "where is activity concentrated" rather than "exactly how many things are at each point." The leaflet.heat plugin renders that as a smooth, blurred intensity surface computed from a set of weighted points — and the weighting is what separates a real heatmap from just a blurry marker cluster.

Each point carries its own weight, not just a position

leaflet.heat's point format is [lat, lng, intensity] — a third value per point beyond the coordinate pair. This snippet generates points around four hotspots with different base weights (Times Square contributes more total points *and* a higher per-point base intensity than Chelsea), so the resulting heat surface reflects genuine relative activity levels, not just how many dots happen to be nearby.

radius and blur are re-applied live, not just at creation

The intensity slider calls heat.setOptions({ radius, blur }) on every input event — both scaled by the same slider value — which re-renders the existing heat layer's visual parameters without touching the underlying point data at all. That's meaningfully cheaper than removing and recreating the whole layer on every slider tick, and it's why the intensity change feels instant even while dragging.

The raw-points toggle is a real credibility check, not a gimmick

Heatmaps can visually oversell sparse data — a handful of points with a large blur radius can look like a solid hot region. Toggling "Show raw points" overlays the actual underlying circleMarker dots, letting a viewer verify that the smooth heat surface really does correspond to real point density and isn't an artifact of an overly generous blur setting.

The raw layer is a genuine LayerGroup, added and removed cleanly

Rather than toggling each dot's visibility individually, all the raw point markers are pre-built into one L.layerGroup(), and the checkbox simply calls rawLayer.addTo(map) or map.removeLayer(rawLayer) — adding or removing the whole group as one unit, which is both simpler code and cheaper than hundreds of individual show/hide operations.

Reusing it

Swap the generated hotspot points for real event data — check-ins, sensor pings, incident reports, delivery stops — keeping the same [lat, lng, weight] shape, and the intensity control and raw-points comparison view keep working unchanged.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out heat-surface rendering yourself. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how leaflet.heat uses each point's third weight value to compute the blended intensity surface, and why calling setOptions to adjust radius and blur is cheaper than recreating the whole heat layer on every slider change. The same assistant can help optimize it — ask whether generating and holding hundreds of raw-point circle markers up front (even while hidden) has a meaningful memory cost worth avoiding for a much larger dataset. It's also useful for extending the effect: ask it to add a time-of-day slider that filters which points are included in the heat calculation, a second heat layer for a comparison time period rendered side by side, or a gradient color scheme picker. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a weighted density heatmap on an interactive map using Leaflet.js with the leaflet.heat plugin (load Leaflet's CSS/JS and the leaflet.heat plugin's JS from a CDN, no other library), in plain HTML, CSS, and JavaScript.

Requirements:
- Generate a set of sample points clustered around several distinct hotspot locations with different relative importance (some hotspots should be busier than others), where each point carries its own coordinate pair plus a numeric weight/intensity value — not just a plain coordinate list.
- Render the points as a heatmap layer where the visual intensity reflects each point's individual weight in addition to how many nearby points there are, using the heatmap plugin's weighted-point format.
- Add an intensity slider that live-adjusts the heatmap's visual radius and blur settings by updating the existing heat layer's rendering options directly, without rebuilding or reprocessing the underlying point data on every slider change.
- Add a checkbox that toggles a raw-points overlay showing the actual individual data points as small markers on top of the heatmap, so a viewer can visually verify that the smooth heat surface accurately reflects the real underlying point density rather than being an artifact of the blur settings. Implement toggling this overlay efficiently as one grouped operation rather than showing/hiding many individual markers separately.
- Use free OpenStreetMap tile layers so the demo requires no API key.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Source Code

<div class="hd-wrap">
  <div class="hd-bar">
    <div class="hd-title">Foot Traffic Density — Last 24h</div>
    <label class="hd-toggle"><input type="checkbox" id="hdPoints"> Show raw points</label>
    <label class="hd-slider">
      Intensity <output id="hdOut">1.0</output>
      <input type="range" id="hdIntensity" min="0.3" max="2" step="0.1" value="1">
    </label>
  </div>
  <div class="hd-map" id="hdMap"></div>
</div>

Step by step

How to Use

  1. 1
    Add the Leaflet and leaflet.heat CDNsleaflet.css, leaflet.js, then leaflet-heat.js.
  2. 2
    Paste HTML, CSS, and JSA weighted heatmap renders over four density hotspots.
  3. 3
    Adjust the intensity sliderThe heat surface's radius and blur update live.
  4. 4
    Check "Show raw points"The actual underlying data points overlay the heat surface.
  5. 5
    Compare the two viewsVerify the smooth heat matches the real point density.
  6. 6
    Zoom and panThe heat layer re-renders to match the new viewport.

Real-world uses

Common Use Cases

Foot traffic and retail analytics
Visualize where customers actually concentrate.
Crime and safety density maps
Incident concentration by neighborhood or block.
Delivery and logistics hotspot analysis
Where drop-offs or pickups cluster most.
Event attendance and crowd density
Real-time or historical crowd concentration views.
Environmental sensor readings
Pair with the GeoJSON choropleth elsewhere in this collection for a region-level companion view.
Learning Leaflet plugins
A clear reference for weighted density visualization.

Got questions?

Frequently Asked Questions

leaflet.heat expects points in the form [latitude, longitude, intensity], where the third value is that specific point's weight or contribution to the overall heat surface. Two points at similar locations but different weights will contribute different amounts of "heat" — this is what lets a heatmap represent genuine relative intensity rather than treating every point as equally significant.

The slider's handler calls heat.setOptions({ radius, blur }), which re-renders the existing heat layer's visual appearance using its already-computed point data — it does not rebuild or reprocess the underlying points array at all. Removing and recreating the entire heat layer with a new radius on every slider input event would be considerably more expensive and would visibly lag during a drag.

A heatmap's smooth, blurred visual can make sparse data look artificially concentrated if the blur radius is generous relative to how few real points exist. Overlaying the actual data points as small markers lets a viewer directly verify that the heat surface's apparent hot regions correspond to real point density, rather than being purely a visual effect of the blur and radius settings.

All the raw-point markers are created once and added to a single L.layerGroup() up front. The checkbox handler then adds or removes that whole group from the map in one call (rawLayer.addTo(map) or map.removeLayer(rawLayer)), which is both simpler to write and cheaper to execute than looping through potentially hundreds of individual markers to show or hide each one separately.

Replace the generated points loop with your own array of [latitude, longitude, weight] triples built from real data — check-in timestamps, sensor readings, incident reports. If your data doesn't have a natural weight value, a constant weight of 1 for every point still produces a valid, purely count-based heatmap; the intensity slider and raw-points toggle work unchanged either way.