惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

TaoSecurity Blog
TaoSecurity Blog
博客园 - 司徒正美
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
罗磊的独立博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Stack Overflow Blog
Stack Overflow Blog
The GitHub Blog
The GitHub Blog
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
宝玉的分享
宝玉的分享
N
News and Events Feed by Topic
The Hacker News
The Hacker News
Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
F
Full Disclosure
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Security @ Cisco Blogs
H
Hacker News: Front Page
L
LangChain Blog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
B
Blog RSS Feed
H
Heimdal Security Blog
Google Online Security Blog
Google Online Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 三生石上(FineUI控件)
V2EX - 技术
V2EX - 技术
V
Vulnerabilities – Threatpost
Help Net Security
Help Net Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Tailwind CSS Blog
W
WeLiveSecurity
T
Tenable Blog
D
DataBreaches.Net
Martin Fowler
Martin Fowler
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
S
Secure Thoughts
O
OpenAI News
L
LINUX DO - 热门话题
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Jina AI
Jina AI
J
Java Code Geeks
Know Your Adversary
Know Your Adversary
IT之家
IT之家
Latest news
Latest news
Cloudbric
Cloudbric

Starred Articles

Improvements to Web for AI Should Benefit All Users New to the web platform in April  |  Blog  |  web.dev Eames Pavilion System Squarespace & Web Standards: How We Helped Bring HTML Video & Audio Lazy Loading to Today’s Browsers | Scott Jehl, Web Designer/Developer The Web is a Guitar Amp Now (Literally) Making keyboard navigation effortless I used Claude Code and GSD to build the accessibility tool I’ve always wanted - blakewatson.com Sizing chaos Scroll indicators on tables with background colours using animation-timeline Webspace Invaders Fresh Hot CSS: Trig Functions The Year Of The Linux Desktop (for fitness games) Almost Plain Text, Nicely Done – Email is good. Uncrate's 100-ish favorite things on Amazon VS Code – highlight just the active indent guide How musicals use motifs to tell stories Good Tidings! Review: MoErgo Go60, a split ergonomic and fully programmable keyboard The line and the stream. — Ethan Marcotte Testing HTML Light DOM Web Components: Easier Than Expected! Enhancing Web Components Safely with Self-Destructing CSS | Scott Jehl, Web Designer/Developer Steam Machine Caira AI Mirrorless Camera A Treatise on AI Chatbots Undermining the Enlightenment Talking CSS, Web Components, App Design and (gulp) AI on ShopTalk Show Microsoft™ Ergonomic Keyboard (now sold by Incase) A new, new logo for the W3C Chris Coyier Solved by CSS Scroll State Queries: hide a header when scrolling down, show it again when scrolling up. closedBy=any · October 16, 2025 Paxos accidentally mints more than twice the global GDP in PayPal stablecoins The CSS Podcast is back! And I’m a co-host now. Who needs a flying car when you have display: grid Junior Dev Tip: "Scroll Up" WWW Ep212 With Dave Rupert · October 2, 2025 DHH Is Way Worse Than I Thought | jakelazaroff.com A custom --light-dark() function in CSS that works with any type of value (not just colors!) in just 3 LOC Make accessible carousels  |  Blog  |  Chrome for Developers 37 pm · Paul Robert Lloyd Against the protection of stocking frames. — Ethan Marcotte “Why would anybody start a website?” Necropolis Should Men Be the Head of Every Household? The History of Themeable User Interfaces Speeding up my Learning Log process Eight years of Jessie How our dog increased my appreciation for accessibility In the Future All Food Will Be Cooked in a Microwave, and if You Can’t Deal With That Then You Need to Get Out of the Kitchen Somewhere Between Lost and Found Impact of AI on Tech Content Creators Progressive Enhancement and Web Components Sizzle Rizzle · July 4, 2025 The Cascade
Delivering a dynamic hexagonal world map in just 10kb | Calibre
Ben Schwarz · 2026-04-22 · via Starred Articles

Ok, let me get this out in the open: I love the new hex map in Calibre, maybe more than I should. Two weeks of wrestling with point-in-polygon calculations, tolerance settings, and the question of whether Tasmania is big enough to fill a 4-pixel hexagon (dear reader, it is not), and I’d do it all again. Let me show you how I built hex map.

Mapping real user sessions by performance#

"Hex map" is a dynamic map visualisation summarising user experience sessions from each country, displayed in the Real User Monitoring (RUM) Audience report.

Calibre’s RUM Audience report. You can see the hex map at the bottom of the image.
Calibre’s RUM Audience report. You can see the hex map at the bottom of the image.

The map is made up of interlocked hexagons, each representing a country. The colour of each country indicates Calibre’s UX Rating, based on overall performance.

As user sessions are observed, countries light up in the map. You can gain a lot of empathy and understanding when segmenting by UX Rating.

The map, cycling through grading colours for fun. It isn’t normally this hectic.

The map, cycling through grading colours for fun. It isn’t normally this hectic.

Design goals#

After viewing maps in products I knew, and surveying existing libraries and paid mapping services, it was clear I wanted something more simple, elegant, and maybe a bit more artistic. The requirements were:

  • Load fast, and feel light-weight
  • Visually display country-level UX Rating
  • Intentionally low-fi, a visual element to enjoy and tell a story
  • Work on all browsers
  • Have light and dark colour mode themes to match the app

Research and inspiration#

With any creative data visualisation project, you want to look for examples in the wild. A few things kept pulling me in: the low-fi blockiness of voxels, numerous beautiful election voter maps, and more abstract geo visualisations.

Voxel geometry, hexagonal maps and abstract geography.

I’ve always enjoyed the datavis used on election nights. Providing valuable illustrations for viewers who likely aren’t used to looking at visualisations is a bit of an art form. Hex cartograms do a great job of compacting data into beautiful visual elements that help tell a story without being too much.

Given a brief of visual simplicity, hexagonal maps were perfect and given my experience with SVG and D3, I knew I could quickly iterate to a high quality map.

Getting the detail right#

I wanted the map to feel blocky and not too detailed. Hexes at about 4 pixels wide felt right, low-fi enough to feel like an illustration rather than a satellite image.

Where the real work came in, was the map data itself. High-resolution geojson is hefty, but can be significantly reduced by simplifying paths (country borders). Oversimplify and countries merge, islands disappear. It’s a balance.

I started with 10 meter accuracy country boundaries and ran them through Turf’s excellent simplify function, iterating on the tolerance until countries were still recognisable at 4 pixels without overwhelming the visual with detail.

An early render of the map with cities highlighted

An early render of the map with cities highlighted

One shape, repeated 2,164 times#

Once the geometry was behaving, it was time to start narrowing into a final working implementation.

I wrote a pipeline in Node.js, it needed to:

  • Source input map data
  • Simplify / compress geojson data
  • Include country names and 2 letter country codes
  • Draw the map using equirectangular projection† (d3-geo)
  • Centre the map with a slight north westward offset
  • Remove Antarctica
  • Render a hexagon grid, locating country boundaries using point-in-polygon and boundary detection for each hex
  • Remove hexes for water
  • Add ARIA roles and labels
  • Render to SVG

Map "projections" are the method used to draw a map. There’s many interesting interpretations of map projections, but most people are familar with equirectangular.

Rendering a static .svg file meant no client-side mapping data, no network calls after the initial load. A purely visual representation in one file.

Because the map is made of one shape repeated thousands of times, I leaned on SVG’s <symbol> and <use> to avoid redrawing it and creating a bloated SVG file. Define the hex once:

<symbol id="hex">...</symbol>

Then reference hex wherever it needs to appear, grouped by country:

<g class="country-group" data-country="AU">
	<use href="#hex" x="..." y="..." />
	<use href="#hex" x="..." y="..." />
</g>

That’s the entire data model, structure and identifiers. The output is a single 144kb SVG. The map is generated each time we build and deploy, gets cached in the CDN, and is compressed down to just 10kb when served with GZip.

Comparing 10kb to full blown maps would be an unfair comparison, as they usually have drag to pan, zoom, tiling, internationalisation, and a lot more features. I won’t make that comparison directly.

Light, dark and glow#

Now that I had a .svg file, I added CSS to specify grading colours, and apply light and dark theming with light-dark:

svg {
	--hex-color: light-dark(var(--brand-grey-100), var(--brand-grey-500));
	--hex-stroke: light-dark(var(--brand-grey-200), var(--brand-grey-700));
	--hex-stroke-width: 1;
	--hex-transition: all 0.2s ease;

	/* also define --hex-good-color, --hex-good-stroke, --hex-needs-improvement-color,--hex-needs-improvement-stroke, --hex-poor-color, --hex-poor-stroke here. */

	& use {
		fill: var(--hex-color);
		stroke: var(--hex-stroke);
		stroke-width: var(--hex-stroke-width);
		transition: var(--hex-transition);
	}
}

Our in-app report page dynamically loads the SVG, and assigns grading colours to each country <g> with CSS variables, e.g.: hex-color: var(--hex-needs-improvement-color). Finalising with radial background to give the countries some glow against the background.

Sorry, Tasmania#

A few things didn’t make it. The United States wraps around the left and right edges of the map. Tasmania isn't large enough to register a 4 pixel dot (sorry mates!). There are many imperfections gained with this particular approach to simplification.

Getting a map that’s perfectly accurate, up-to-date with every disputed territory, aligned with our geolocation dataset, fast, and nice to look at would require a cartographer, a geopolitical advisor, and a lot more than two weeks. I am none of those things.

What the map does do: show users where their audience is and how they’re doing. And I love it.

If you want to see the map in action, sign up for a free trial and add real user monitoring to your website.