1// Power plants layer: reads committed JSON from the data pipeline 2// (scripts/data/update-power-plants.mjs â data/power-plants.latest.json). 3// Points colored by fuel type, sized by capacity (capped). 4 5const DATA_URL = "data/power-plants.latest.json"; 6 7const FUEL_COLORS = { 8 Solar: [251, 191, 36], 9 Hydro: [59, 130, 246], 10 Wind: [45, 212, 191], 11 Gas: [251, 146, 60], 12 Coal: [120, 113, 108], 13 Oil: [168, 85, 247], 14 Biomass: [63, 217, 143], 15 Waste: [148, 163, 184], 16 Nuclear: [236, 72, 153], 17 Geothermal: [239, 68, 68], 18 Storage: [99, 102, 241], 19 Other: [161, 161, 170], 20 Cogeneration:[217, 119, 6], 21 Petcoke: [87, 83, 78], 22 "Wave and Tidal": [34, 197, 94], 23}; 24 25export class PowerPlantsLayer { 26 constructor(viewer) { 27 this.viewer = viewer; 28 this.points = viewer.scene.primitives.add(new Cesium.PointPrimitiveCollection()); 29 this.plants = []; 30 this.source = "loading"; 31 this.visible = false; 32 this.loaded = false; 33 this.fuels = []; 34 } 35 36 async init() { 37 this.points.show = false; 38 try { 39 const resp = await fetch(DATA_URL); 40 if (!resp.ok) throw new Error(`${DATA_URL} HTTP ${resp.status}`); 41 const data = await resp.json(); 42 this._build(data); 43 this.source = "data"; 44 this.loaded = true; 45 } catch (e) { 46 console.warn("[power-plants] data load failed:", e.message); 47 this.source = "idle"; 48 } 49 } 50 51 _build(data) { 52 this.fuels = data.meta?.fuels ?? []; 53 const plants = data.plants ?? []; 54 for (const [lon, lat, fuelIdx, mw, name, country] of plants) { 55 const fuelName = this.fuels[fuelIdx] ?? "Other"; 56 const color = FUEL_COLORS[fuelName] ?? FUEL_COLORS.Other; 57 // Size: 4 + sqrt(mw)/4, capped at 14 58 const size = Math.max(3, Math.min(14, 4 + Math.sqrt(mw) / 4)); 59 const point = this.points.add({ 60 position: Cesium.Cartesian3.fromDegrees(lon, lat), 61 pixelSize: size, 62 color: Cesium.Color.fromBytes(color[0], color[1], color[2], 200), 63 outlineColor: Cesium.Color.fromBytes(color[0], color[1], color[2], 80), 64 outlineWidth: 1, 65 scaleByDistance: new Cesium.NearFarScalar(2.0e5, 1.4, 5.0e7, 0.4), 66 id: { kind: "plant", plant: null }, 67 show: this.visible, 68 }); 69 const p = { lon, lat, fuel: fuelName, mw, name, country, point }; 70 point.id = { kind: "plant", plant: p }; 71 this.plants.push(p); 72 } 73 } 74 75 setVisible(v) { 76 this.visible = v; 77 this.points.show = v; 78 } 79 80 counts() { 81 return { 82 count: this.visible ? this.plants.length : 0, 83 source: this.source, 84 detail: `${this.plants.length} plants · WRI GPPD`, 85 }; 86 } 87}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.