import React from "react";
import { Crosshair } from "lucide-react";
import * as Cesium from "cesium";
import { Entity, EllipseGraphics } from "resium";
import {
createSvgIconUrl,
type WorldPlugin, type GeoEntity, type TimeRange,
type PluginContext, type LayerConfig, type CesiumEntityOptions,
type FilterDefinition,
} from "@worldwideview/wwv-plugin-sdk";
import { CONFLICT_ZONES } from "./zones";
function severityToColor(score: number): string {
if (score >= 5) return "#991b1b"; // Critical — dark red
if (score >= 4) return "#ef4444"; // High — red
if (score >= 3) return "#f97316"; // Elevated — orange
return "#fbbf24"; // Monitoring — yellow
}
/** Attach _wwvEntity to a Resium Entity ref so InteractionHandler can pick it. */
function bindWwvEntity(ref: any, geoEntity: GeoEntity): void {
const cesiumEntity = ref?.cesiumElement;
if (cesiumEntity && !cesiumEntity._wwvEntity) {
cesiumEntity._wwvEntity = geoEntity;
}
}
/** Build a synthetic GeoEntity from a static ConflictZone definition. */
function zoneToGeoEntity(zone: typeof CONFLICT_ZONES[number]): GeoEntity {
return {
id: zone.id,
pluginId: "conflict-zones",
latitude: zone.lat,
longitude: zone.lon,
altitude: 0,
timestamp: new Date(),
properties: {
name: zone.name,
description: zone.description,
type: zone.subtext || "N/A",
status: zone.status,
escalationScore: zone.escalationScore,
escalationTrend: zone.escalationTrend,
whyItMatters: zone.whyItMatters,
radiusKm: zone.radiusKm,
},
};
}
const ConflictZonesRenderer: React.FC<{ viewer: Cesium.Viewer | null; enabled: boolean }> = ({ enabled }) => {
if (!enabled) return null;
return (
<>
{CONFLICT_ZONES.map(zone => {
const position = Cesium.Cartesian3.fromDegrees(zone.lon, zone.lat);
const colorHex = severityToColor(zone.escalationScore);
const fillColor = Cesium.Color.fromCssColorString(colorHex).withAlpha(0.25);
const outlineColor = Cesium.Color.fromCssColorString(colorHex).withAlpha(0.8);
const radiusMeters = zone.radiusKm * 1000;
const geoEntity = zoneToGeoEntity(zone);
return (
bindWwvEntity(ref, geoEntity)}
>
);
})}
>
);
};
export class ConflictZonesPlugin implements WorldPlugin {
id = "conflict-zones";
name = "Conflict Zones";
description = "Active conflict zones and geopolitical hotspots worldwide.";
icon = Crosshair;
category = "conflict" as const;
version = "1.0.0";
private iconUrls: Record = {};
async initialize(_ctx: PluginContext): Promise { }
destroy(): void { }
async fetch(_tr: TimeRange): Promise { return []; }
getPollingInterval(): number { return 0; }
getLayerConfig(): LayerConfig {
return { color: "#ef4444", clusterEnabled: false, clusterDistance: 0 };
}
renderEntity(entity: GeoEntity): CesiumEntityOptions {
const score = (entity.properties.escalationScore as number) || 3;
const color = severityToColor(score);
if (!this.iconUrls[color]) {
this.iconUrls[color] = createSvgIconUrl(Crosshair, { color });
}
return { type: "billboard", iconUrl: this.iconUrls[color], color };
}
getFilterDefinitions(): FilterDefinition[] {
return [
{
id: "severity", label: "Severity", type: "select", propertyKey: "escalationScore",
options: [
{ value: "5", label: "Critical" },
{ value: "4", label: "High Tension" },
{ value: "3", label: "Elevated" },
{ value: "2", label: "Watchlist" },
],
},
{
id: "trend", label: "Trend", type: "select", propertyKey: "escalationTrend",
options: [
{ value: "escalating", label: "Escalating" },
{ value: "stable", label: "Stable" },
{ value: "de-escalating", label: "De-escalating" },
],
},
];
}
getGlobeComponent() {
return ConflictZonesRenderer;
}
}