| Server IP : 69.72.244.102 / Your IP : 216.73.216.164 Web Server : LiteSpeed System : Linux s3434.fra1.stableserver.net 4.18.0-513.24.1.lve.2.el8.x86_64 #1 SMP Fri May 24 12:42:50 UTC 2024 x86_64 User : konzalta ( 1271) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/konzalta/www/data-visualization/ |
Upload File : |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Budget Mtaani County Voronoi Demo</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<style>
body{margin:0;font-family:Inter,Arial,sans-serif;background:#efefef;color:#151515}
.bm-story-section{min-height:100vh;display:grid;grid-template-columns:.9fr 1.1fr;align-items:center;gap:64px;padding:80px 8vw;background:#efefef}
.bm-story-copy{max-width:560px}.bm-eyebrow{font-size:.85rem;font-weight:900;letter-spacing:.08em;text-transform:uppercase;color:#9b1c31;margin-bottom:18px}
.bm-story-title{font-size:clamp(2.6rem,5vw,5.4rem);line-height:.98;letter-spacing:-.05em;margin:0 0 28px;color:#151515;font-weight:900}
.bm-story-text{font-size:1.15rem;line-height:1.65;color:#333;margin-bottom:24px}
.bm-human-question{font-size:1.05rem;font-weight:800;padding:16px 18px;border-left:5px solid #118c4f;background:#f4fbf7;margin:28px 0}
.bm-story-button{display:inline-flex;align-items:center;padding:15px 28px;border-radius:999px;background:linear-gradient(135deg,#f26b2f,#8e3fd1);color:#fff;font-weight:800;text-decoration:none;border:none;cursor:pointer}
.bm-story-visual{position:relative;background:#f7f4eb;border-radius:18px;padding:16px;box-shadow:0 12px 35px rgba(0,0,0,.08)}
.bm-voronoi-wrap{position:relative}.bm-voronoi{width:100%;height:auto;display:block;border-radius:10px;background:#f7f4eb}
.bm-map-tooltip{position:absolute;background:#111;color:#fff;padding:10px 12px;border-radius:12px;font-weight:800;font-size:14px;box-shadow:0 10px 22px rgba(0,0,0,.25);z-index:10;pointer-events:none;display:none;max-width:220px}
.bm-map-legend{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px;font-size:13px;font-weight:800}.bm-map-legend i{width:18px;height:18px;border-radius:4px;display:inline-block;margin-right:4px;vertical-align:middle}
.bm-map-note{font-size:12px;color:#666;margin-top:12px}.bm-county-result{background:#111;color:#fff;border-radius:18px;padding:18px 20px;font-weight:800;margin-top:14px}.bm-county-select{width:100%;padding:14px 16px;border:2px solid #ddd;border-radius:14px;font-weight:800;margin-bottom:16px}
.bm-voronoi path{cursor:pointer;stroke:#fff;stroke-width:1.4;transition:.18s}.bm-voronoi path:hover,.bm-voronoi path.is-active{filter:brightness(.92);stroke:#111;stroke-width:2.2}
.bm-voronoi text{font-size:10px;font-weight:800;fill:#222;pointer-events:none}
@media(max-width:900px){.bm-story-section{grid-template-columns:1fr;gap:32px;padding:56px 24px}.bm-story-title{font-size:clamp(2.3rem,12vw,4rem)}}
</style>
</head>
<body>
<section class="bm-story-section">
<div class="bm-story-copy">
<div class="bm-eyebrow">Budget Mtaani</div>
<h1 class="bm-story-title">County Yako Imepata Ngapi?</h1>
<p class="bm-story-text">Hii ni Voronoi view ya mgao wa county. Kila cell inawakilisha county moja kwa kutumia pointi ya kati, kisha eneo linakatwa ndani ya umbo la Kenya. Ni njia nzuri ya kuonyesha mgao kwa namna ya kisasa na rahisi kusoma.</p>
<div class="bm-human-question">Hii inakuhusu aje? Bonyeza county yako uone imepata kiasi gani na uulize: pesa hii itaonekana kwa huduma za afya, maji, soko na barabara ndogo?</div>
<select class="bm-county-select"><option value="">Chagua county...</option></select>
<button class="bm-story-button" type="button" onclick="document.querySelector('.bm-story-visual').scrollIntoView({behavior:'smooth'})">Explore the map</button>
<div class="bm-county-result">Chagua county kwenye ramani au kwenye orodha.</div>
</div>
<div class="bm-story-visual">
<div class="bm-voronoi-wrap">
<div class="bm-map-tooltip"></div>
<svg class="bm-voronoi" viewBox="0 0 920 720" role="img" aria-label="Kenya county allocation Voronoi diagram"></svg>
</div>
<div class="bm-map-legend"><span><i style="background:#f7fcb9"></i>Below 6B</span><span><i style="background:#c7e9c0"></i>6–7.9B</span><span><i style="background:#74c476"></i>8–10.9B</span><span><i style="background:#238b45"></i>11–13.9B</span><span><i style="background:#14532d"></i>14B+</span></div>
<p class="bm-map-note">Prototype note: Voronoi cells are generated from county centroids and clipped to the prototype Kenya outline. For launch, use accurate county boundaries/centroids as the source.</p>
</div>
</section>
<script>
const GEOJSON_URL='kenya-counties-budget-mtaani-voronoi.geojson';
const W=920,H=720,pad=28;
function color(v){ if(v>=14)return '#14532d'; if(v>=11)return '#238b45'; if(v>=8)return '#74c476'; if(v>=6)return '#c7e9c0'; return '#f7fcb9'; }
function bounds(features){let xs=[],ys=[];function scan(c){ if(typeof c[0]==='number'){xs.push(c[0]);ys.push(c[1]);} else c.forEach(scan); } features.forEach(f=>scan(f.geometry.coordinates)); return [Math.min(...xs),Math.min(...ys),Math.max(...xs),Math.max(...ys)];}
function projector(b){const [minx,miny,maxx,maxy]=b;const scale=Math.min((W-2*pad)/(maxx-minx),(H-2*pad)/(maxy-miny));const mapw=(maxx-minx)*scale,maph=(maxy-miny)*scale;const xoff=(W-mapw)/2,yoff=(H-maph)/2;return (x,y)=>[xoff+(x-minx)*scale,yoff+(maxy-y)*scale];}
function ringPath(ring,proj){return ring.map((p,i)=>{const [x,y]=proj(p[0],p[1]);return (i?'L':'M')+x.toFixed(2)+','+y.toFixed(2);}).join(' ')+' Z';}
function geomPath(g,proj){let out=[]; if(g.type==='Polygon') g.coordinates.forEach(r=>out.push(ringPath(r,proj))); if(g.type==='MultiPolygon') g.coordinates.forEach(poly=>poly.forEach(r=>out.push(ringPath(r,proj)))); return out.join(' ');}
function centroid(g){function pts(coords,a=[]){ if(typeof coords[0]==='number') a.push(coords); else coords.forEach(c=>pts(c,a)); return a;} const p=pts(g.coordinates,[]); let x=0,y=0; p.forEach(pt=>{x+=pt[0];y+=pt[1];}); return [x/p.length,y/p.length]; }
fetch(GEOJSON_URL).then(r=>r.json()).then(data=>{
const feats=data.features.sort((a,b)=>a.properties.county_name.localeCompare(b.properties.county_name));
const proj=projector(bounds(feats));
const svg=document.querySelector('.bm-voronoi'); const tip=document.querySelector('.bm-map-tooltip'); const res=document.querySelector('.bm-county-result'); const sel=document.querySelector('.bm-county-select');
feats.forEach(f=>{const p=f.properties; const opt=document.createElement('option'); opt.value=p.county_name; opt.textContent=p.county_name; sel.appendChild(opt);
const path=document.createElementNS('http://www.w3.org/2000/svg','path'); path.setAttribute('d',geomPath(f.geometry,proj)); path.setAttribute('fill',color(+p.equitable_share_ksh_billion)); path.dataset.county=p.county_name; path.dataset.amount=p.equitable_share_ksh_billion; path.dataset.rank=p.allocation_rank;
path.addEventListener('click',()=>choose(p.county_name)); path.addEventListener('mousemove',e=>{tip.style.display='block'; tip.style.left=(e.offsetX+20)+'px'; tip.style.top=(e.offsetY+20)+'px'; tip.innerHTML=`${p.county_name}<br>Ksh ${Number(p.equitable_share_ksh_billion).toFixed(1)}B<br>Rank #${p.allocation_rank}`;}); path.addEventListener('mouseleave',()=>tip.style.display='none'); svg.appendChild(path);
const c=centroid(f.geometry); const [lx,ly]=proj(c[0],c[1]); const txt=document.createElementNS('http://www.w3.org/2000/svg','text'); txt.setAttribute('x',lx); txt.setAttribute('y',ly); txt.setAttribute('text-anchor','middle'); txt.textContent=p.county_name; svg.appendChild(txt); });
function choose(name){const f=feats.find(x=>x.properties.county_name===name); if(!f) return; const p=f.properties; sel.value=name; svg.querySelectorAll('path').forEach(x=>x.classList.toggle('is-active',x.dataset.county===name)); res.innerHTML=`<strong>${p.story_label}</strong><br><span>Rank #${p.allocation_rank} kwa mgao wa county. ${p.simple_explanation}</span>`;}
sel.addEventListener('change',e=>choose(e.target.value));
});
</script>
</body></html>