85453da49f
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Docs / Validate docs (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Sync skills to ClawHub / Publish changed skills (push) Waiting to run
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
478 lines
15 KiB
HTML
Vendored
478 lines
15 KiB
HTML
Vendored
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=1920, height=1080" />
|
|
<title>US Bubble Map</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=block"
|
|
rel="stylesheet"
|
|
/>
|
|
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/topojson-client@3.1.0/dist/topojson-client.min.js"></script>
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
width: 1920px;
|
|
height: 1080px;
|
|
overflow: hidden;
|
|
background-color: #0f172a;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div
|
|
id="us-map-bubble"
|
|
data-composition-id="us-map-bubble"
|
|
data-width="1920"
|
|
data-height="1080"
|
|
data-start="0"
|
|
data-duration="12"
|
|
>
|
|
<div class="map-container">
|
|
<div class="header">
|
|
<h1 class="headline">Top 20 US Cities by Population</h1>
|
|
<p class="subtitle">Proportional bubble markers by metropolitan population</p>
|
|
</div>
|
|
|
|
<svg class="map-svg" viewBox="0 0 1400 820" preserveAspectRatio="xMidYMid meet">
|
|
<g class="states-group"></g>
|
|
<g class="connections-group"></g>
|
|
<g class="bubbles-group"></g>
|
|
<g class="callouts-group"></g>
|
|
</svg>
|
|
|
|
<div class="source">Source: U.S. Census Bureau, 2024</div>
|
|
</div>
|
|
|
|
<style>
|
|
#us-map-bubble {
|
|
width: 1920px;
|
|
height: 1080px;
|
|
background: linear-gradient(145deg, #0f172a 0%, #1e293b 100%);
|
|
font-family: "Inter", sans-serif;
|
|
color: #e2e8f0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
}
|
|
|
|
#us-map-bubble .map-container {
|
|
width: 1700px;
|
|
height: 950px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
position: relative;
|
|
}
|
|
|
|
#us-map-bubble .header {
|
|
text-align: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
#us-map-bubble .headline {
|
|
font-size: 52px;
|
|
font-weight: 700;
|
|
letter-spacing: -0.02em;
|
|
color: #f8fafc;
|
|
clip-path: inset(0 100% 0 0);
|
|
}
|
|
|
|
#us-map-bubble .subtitle {
|
|
font-size: 20px;
|
|
font-weight: 300;
|
|
color: #94a3b8;
|
|
margin-top: 8px;
|
|
opacity: 0;
|
|
}
|
|
|
|
#us-map-bubble .map-svg {
|
|
width: 1500px;
|
|
height: 750px;
|
|
overflow: visible;
|
|
}
|
|
|
|
#us-map-bubble .state-path {
|
|
fill: #1e293b;
|
|
stroke: #334155;
|
|
stroke-width: 0.5;
|
|
opacity: 0;
|
|
}
|
|
|
|
#us-map-bubble .city-bubble {
|
|
fill: rgba(59, 130, 246, 0.6);
|
|
stroke: #ffffff;
|
|
stroke-width: 1;
|
|
transform-origin: center center;
|
|
transform: scale(0);
|
|
}
|
|
|
|
#us-map-bubble .city-pulse {
|
|
fill: none;
|
|
stroke: rgba(59, 130, 246, 0.4);
|
|
stroke-width: 2;
|
|
opacity: 0;
|
|
}
|
|
|
|
#us-map-bubble .callout-group {
|
|
opacity: 0;
|
|
}
|
|
|
|
#us-map-bubble .callout-line {
|
|
stroke: rgba(148, 163, 184, 0.5);
|
|
stroke-width: 1;
|
|
fill: none;
|
|
}
|
|
|
|
#us-map-bubble .callout-name {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
fill: #f8fafc;
|
|
}
|
|
|
|
#us-map-bubble .callout-value {
|
|
font-size: 11px;
|
|
font-weight: 400;
|
|
fill: #94a3b8;
|
|
}
|
|
|
|
#us-map-bubble .connection-line {
|
|
stroke: rgba(59, 130, 246, 0.3);
|
|
stroke-width: 1;
|
|
fill: none;
|
|
stroke-dasharray: 6 4;
|
|
}
|
|
|
|
#us-map-bubble .source {
|
|
position: absolute;
|
|
bottom: 0;
|
|
right: 40px;
|
|
font-size: 12px;
|
|
color: #475569;
|
|
opacity: 0;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
(function () {
|
|
var US_TOPO_URL = "https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json";
|
|
|
|
var cities = [
|
|
{ name: "New York", lat: 40.7128, lon: -74.006, pop: 8300000 },
|
|
{ name: "Los Angeles", lat: 34.0522, lon: -118.2437, pop: 3900000 },
|
|
{ name: "Chicago", lat: 41.8781, lon: -87.6298, pop: 2700000 },
|
|
{ name: "Houston", lat: 29.7604, lon: -95.3698, pop: 2300000 },
|
|
{ name: "Phoenix", lat: 33.4484, lon: -112.074, pop: 1600000 },
|
|
{ name: "Philadelphia", lat: 39.9526, lon: -75.1652, pop: 1600000 },
|
|
{ name: "San Antonio", lat: 29.4241, lon: -98.4936, pop: 1400000 },
|
|
{ name: "San Diego", lat: 32.7157, lon: -117.1611, pop: 1400000 },
|
|
{ name: "Dallas", lat: 32.7767, lon: -96.797, pop: 1300000 },
|
|
{ name: "Jacksonville", lat: 30.3322, lon: -81.6557, pop: 950000 },
|
|
{ name: "Austin", lat: 30.2672, lon: -97.7431, pop: 960000 },
|
|
{ name: "San Jose", lat: 37.3382, lon: -121.8863, pop: 1000000 },
|
|
{ name: "Fort Worth", lat: 32.7555, lon: -97.3308, pop: 930000 },
|
|
{ name: "Columbus", lat: 39.9612, lon: -82.9988, pop: 910000 },
|
|
{ name: "Charlotte", lat: 35.2271, lon: -80.8431, pop: 870000 },
|
|
{ name: "Indianapolis", lat: 39.7684, lon: -86.1581, pop: 880000 },
|
|
{ name: "San Francisco", lat: 37.7749, lon: -122.4194, pop: 870000 },
|
|
{ name: "Seattle", lat: 47.6062, lon: -122.3321, pop: 740000 },
|
|
{ name: "Denver", lat: 39.7392, lon: -104.9903, pop: 710000 },
|
|
{ name: "Nashville", lat: 36.1627, lon: -86.7816, pop: 690000 },
|
|
];
|
|
|
|
var radiusScale = d3.scaleSqrt().domain([500000, 8500000]).range([6, 45]);
|
|
|
|
var svg = document.querySelector("#us-map-bubble .map-svg");
|
|
var statesGroup = svg.querySelector(".states-group");
|
|
var bubblesGroup = svg.querySelector(".bubbles-group");
|
|
var calloutsGroup = svg.querySelector(".callouts-group");
|
|
var connectionsGroup = svg.querySelector(".connections-group");
|
|
var tl = gsap.timeline({ paused: true });
|
|
|
|
function formatPop(n) {
|
|
if (n >= 1000000) {
|
|
return (n / 1000000).toFixed(1) + "M";
|
|
}
|
|
return (n / 1000).toFixed(0) + "K";
|
|
}
|
|
|
|
fetch(US_TOPO_URL)
|
|
.then(function (r) {
|
|
return r.json();
|
|
})
|
|
.then(function (us) {
|
|
var states = topojson.feature(us, us.objects.states).features;
|
|
var projection = d3.geoAlbersUsa().fitSize([1380, 800], {
|
|
type: "FeatureCollection",
|
|
features: states,
|
|
});
|
|
var path = d3.geoPath().projection(projection);
|
|
|
|
states.forEach(function (feature) {
|
|
var d = path(feature);
|
|
if (!d) return;
|
|
|
|
var el = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
el.setAttribute("d", d);
|
|
el.setAttribute("class", "state-path");
|
|
statesGroup.appendChild(el);
|
|
});
|
|
|
|
var projectedCities = [];
|
|
cities.forEach(function (city) {
|
|
var coords = projection([city.lon, city.lat]);
|
|
if (!coords) return;
|
|
projectedCities.push({
|
|
name: city.name,
|
|
pop: city.pop,
|
|
x: coords[0],
|
|
y: coords[1],
|
|
r: radiusScale(city.pop),
|
|
});
|
|
});
|
|
|
|
projectedCities.sort(function (a, b) {
|
|
return b.pop - a.pop;
|
|
});
|
|
|
|
var nycCoords = null;
|
|
projectedCities.forEach(function (city) {
|
|
if (city.name === "New York") {
|
|
nycCoords = { x: city.x, y: city.y };
|
|
}
|
|
});
|
|
|
|
var connectionTargets = ["Los Angeles", "Chicago", "Houston", "Phoenix"];
|
|
connectionTargets.forEach(function (targetName) {
|
|
if (!nycCoords) return;
|
|
var target = null;
|
|
projectedCities.forEach(function (c) {
|
|
if (c.name === targetName) target = c;
|
|
});
|
|
if (!target) return;
|
|
|
|
var midX = (nycCoords.x + target.x) / 2;
|
|
var midY = Math.min(nycCoords.y, target.y) - 60;
|
|
|
|
var pathD =
|
|
"M " +
|
|
nycCoords.x +
|
|
" " +
|
|
nycCoords.y +
|
|
" Q " +
|
|
midX +
|
|
" " +
|
|
midY +
|
|
" " +
|
|
target.x +
|
|
" " +
|
|
target.y;
|
|
|
|
var line = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
line.setAttribute("d", pathD);
|
|
line.setAttribute("class", "connection-line");
|
|
connectionsGroup.appendChild(line);
|
|
|
|
var length = line.getTotalLength();
|
|
line.style.strokeDasharray = length;
|
|
line.style.strokeDashoffset = length;
|
|
});
|
|
|
|
projectedCities.forEach(function (city) {
|
|
var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
circle.setAttribute("cx", city.x);
|
|
circle.setAttribute("cy", city.y);
|
|
circle.setAttribute("r", city.r);
|
|
circle.setAttribute("class", "city-bubble");
|
|
circle.setAttribute("data-city", city.name);
|
|
bubblesGroup.appendChild(circle);
|
|
});
|
|
|
|
var pulseCircle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
if (nycCoords) {
|
|
pulseCircle.setAttribute("cx", nycCoords.x);
|
|
pulseCircle.setAttribute("cy", nycCoords.y);
|
|
pulseCircle.setAttribute("r", radiusScale(8300000));
|
|
pulseCircle.setAttribute("class", "city-pulse");
|
|
bubblesGroup.appendChild(pulseCircle);
|
|
}
|
|
|
|
var top5 = projectedCities.slice(0, 5);
|
|
top5.forEach(function (city, i) {
|
|
var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
g.setAttribute("class", "callout-group");
|
|
|
|
var offsetX = city.r + 12;
|
|
var offsetY = -8;
|
|
|
|
if (city.name === "Los Angeles" || city.name === "San Francisco") {
|
|
offsetX = -(city.r + 80);
|
|
}
|
|
|
|
var calloutLine = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
calloutLine.setAttribute("x1", city.x);
|
|
calloutLine.setAttribute("y1", city.y);
|
|
calloutLine.setAttribute("x2", city.x + offsetX);
|
|
calloutLine.setAttribute("y2", city.y + offsetY);
|
|
calloutLine.setAttribute("class", "callout-line");
|
|
g.appendChild(calloutLine);
|
|
|
|
var nameText = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
nameText.setAttribute("x", city.x + offsetX + (offsetX > 0 ? 6 : -6));
|
|
nameText.setAttribute("y", city.y + offsetY - 2);
|
|
nameText.setAttribute("class", "callout-name");
|
|
if (offsetX < 0) {
|
|
nameText.setAttribute("text-anchor", "end");
|
|
}
|
|
nameText.textContent = city.name;
|
|
g.appendChild(nameText);
|
|
|
|
var valueText = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
valueText.setAttribute("x", city.x + offsetX + (offsetX > 0 ? 6 : -6));
|
|
valueText.setAttribute("y", city.y + offsetY + 14);
|
|
valueText.setAttribute("class", "callout-value");
|
|
if (offsetX < 0) {
|
|
valueText.setAttribute("text-anchor", "end");
|
|
}
|
|
valueText.textContent = formatPop(city.pop) + " residents";
|
|
g.appendChild(valueText);
|
|
|
|
calloutsGroup.appendChild(g);
|
|
});
|
|
|
|
buildTimeline(projectedCities, pulseCircle);
|
|
});
|
|
|
|
function buildTimeline(projectedCities, pulseCircle) {
|
|
var statePaths = statesGroup.querySelectorAll(".state-path");
|
|
var bubbles = bubblesGroup.querySelectorAll(".city-bubble");
|
|
var callouts = calloutsGroup.querySelectorAll(".callout-group");
|
|
var connections = connectionsGroup.querySelectorAll(".connection-line");
|
|
|
|
tl.to(
|
|
"#us-map-bubble .headline",
|
|
{
|
|
clipPath: "inset(0 0% 0 0)",
|
|
duration: 1.0,
|
|
ease: "power2.inOut",
|
|
},
|
|
0,
|
|
);
|
|
|
|
tl.to(
|
|
"#us-map-bubble .subtitle",
|
|
{
|
|
opacity: 1,
|
|
duration: 0.6,
|
|
ease: "power2.out",
|
|
},
|
|
0.4,
|
|
);
|
|
|
|
tl.to(
|
|
statePaths,
|
|
{
|
|
opacity: 0.8,
|
|
duration: 0.6,
|
|
ease: "power2.out",
|
|
},
|
|
0.8,
|
|
);
|
|
|
|
tl.to(
|
|
bubbles,
|
|
{
|
|
scale: 1,
|
|
duration: 0.5,
|
|
stagger: {
|
|
each: 0.08,
|
|
from: "start",
|
|
},
|
|
ease: "back.out(1.7)",
|
|
},
|
|
1.5,
|
|
);
|
|
|
|
tl.set(callouts, { x: 20 }, 3.9);
|
|
|
|
tl.to(
|
|
callouts,
|
|
{
|
|
opacity: 1,
|
|
x: 0,
|
|
duration: 0.6,
|
|
stagger: 0.3,
|
|
ease: "power2.out",
|
|
},
|
|
4.0,
|
|
);
|
|
|
|
connections.forEach(function (line) {
|
|
tl.to(
|
|
line,
|
|
{
|
|
strokeDashoffset: 0,
|
|
duration: 1.2,
|
|
ease: "power2.inOut",
|
|
},
|
|
6.0,
|
|
);
|
|
});
|
|
|
|
if (pulseCircle) {
|
|
tl.to(
|
|
pulseCircle,
|
|
{
|
|
opacity: 1,
|
|
duration: 0.01,
|
|
},
|
|
8.0,
|
|
);
|
|
|
|
tl.fromTo(
|
|
pulseCircle,
|
|
{
|
|
attr: { r: radiusScale(8300000) },
|
|
opacity: 0.6,
|
|
},
|
|
{
|
|
attr: { r: radiusScale(8300000) + 30 },
|
|
opacity: 0,
|
|
duration: 1.5,
|
|
repeat: 2,
|
|
ease: "power2.out",
|
|
},
|
|
8.0,
|
|
);
|
|
}
|
|
|
|
tl.to(
|
|
"#us-map-bubble .source",
|
|
{
|
|
opacity: 1,
|
|
duration: 0.5,
|
|
ease: "power2.out",
|
|
},
|
|
5.5,
|
|
);
|
|
|
|
window.__timelines = window.__timelines || {};
|
|
window.__timelines["us-map-bubble"] = tl;
|
|
}
|
|
})();
|
|
</script>
|
|
</div>
|
|
</body>
|
|
</html>
|