fix: 修复移动端报错
This commit is contained in:
@@ -9,6 +9,9 @@ import {
|
||||
Rocket,
|
||||
Asterisk,
|
||||
Amphora,
|
||||
Layers,
|
||||
Sailboat,
|
||||
Warehouse,
|
||||
} from 'lucide-react'
|
||||
import type { CombatLosses } from '@/data/mockData'
|
||||
|
||||
@@ -25,6 +28,9 @@ export function CombatLossesOtherPanel({ usLosses, iranLosses, className = '' }:
|
||||
{ label: '战舰', icon: Ship, iconColor: 'text-blue-500', us: usLosses.warships, ir: iranLosses.warships },
|
||||
{ label: '装甲', icon: Shield, iconColor: 'text-emerald-500', us: usLosses.armor, ir: iranLosses.armor },
|
||||
{ label: '车辆', icon: Car, iconColor: 'text-slate-400', us: usLosses.vehicles, ir: iranLosses.vehicles },
|
||||
{ label: '坦克', icon: Layers, iconColor: 'text-amber-600', us: usLosses.tanks ?? 0, ir: iranLosses.tanks ?? 0 },
|
||||
{ label: '民船', icon: Sailboat, iconColor: 'text-cyan-400', us: usLosses.civilianShips ?? 0, ir: iranLosses.civilianShips ?? 0 },
|
||||
{ label: '机/港', icon: Warehouse, iconColor: 'text-orange-400', us: usLosses.airportPort ?? 0, ir: iranLosses.airportPort ?? 0 },
|
||||
{ label: '无人机', icon: Drone, iconColor: 'text-violet-400', us: usLosses.drones ?? 0, ir: iranLosses.drones ?? 0 },
|
||||
{ label: '导弹', icon: Rocket, iconColor: 'text-orange-500', us: usLosses.missiles ?? 0, ir: iranLosses.missiles ?? 0 },
|
||||
{ label: '直升机', icon: Asterisk, iconColor: 'text-teal-400', us: usLosses.helicopters ?? 0, ir: iranLosses.helicopters ?? 0 },
|
||||
|
||||
@@ -127,11 +127,25 @@ function toFeature(loc: KeyLoc, side: 'us' | 'iran', status?: BaseStatus) {
|
||||
|
||||
const FLIGHT_DURATION_MS = 2500 // 光点飞行单程时间
|
||||
|
||||
/** 移动端/小屏降低动画更新频率以减轻卡顿;返回最小间隔 ms */
|
||||
function getAnimIntervalMs(): number {
|
||||
try {
|
||||
if (typeof window === 'undefined') return 33
|
||||
const reducedMotion =
|
||||
window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
||||
if (reducedMotion) return 100 // 约 10fps,兼顾可访问性
|
||||
return window.innerWidth <= 768 ? 50 : 33 // 移动端约 20fps,桌面约 30fps
|
||||
} catch {
|
||||
return 33
|
||||
}
|
||||
}
|
||||
|
||||
export function WarMap() {
|
||||
const mapRef = useRef<MapRef>(null)
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
const animRef = useRef<number>(0)
|
||||
const startRef = useRef<number>(0)
|
||||
const lastAnimUpdateRef = useRef<number>(0)
|
||||
const attackPathsRef = useRef<[number, number][][]>([])
|
||||
const lincolnPathsRef = useRef<[number, number][][]>([])
|
||||
const fordPathsRef = useRef<[number, number][][]>([])
|
||||
@@ -293,10 +307,15 @@ export function WarMap() {
|
||||
|
||||
const tick = (t: number) => {
|
||||
const elapsed = t - startRef.current
|
||||
const zoom = map.getZoom()
|
||||
const zoomScale = Math.max(0.5, zoom / 4.2) // 随镜头缩放:放大变大、缩小变小(4.2 为默认 zoom)
|
||||
try {
|
||||
// 光点从起点飞向目标的循环动画
|
||||
const intervalMs = getAnimIntervalMs()
|
||||
const shouldUpdate = t - lastAnimUpdateRef.current >= intervalMs
|
||||
if (shouldUpdate) lastAnimUpdateRef.current = t
|
||||
|
||||
if (shouldUpdate) {
|
||||
const zoom = map.getZoom()
|
||||
const zoomScale = Math.max(0.5, zoom / 4.2) // 随镜头缩放:放大变大、缩小变小(4.2 为默认 zoom)
|
||||
try {
|
||||
// 光点从起点飞向目标的循环动画
|
||||
const src = map.getSource('attack-dots') as { setData: (d: GeoJSON.FeatureCollection) => void } | undefined
|
||||
const paths = attackPathsRef.current
|
||||
if (src && paths.length > 0) {
|
||||
@@ -408,7 +427,8 @@ export function WarMap() {
|
||||
map.setPaintProperty('gdelt-events-red-pulse', 'circle-radius', r)
|
||||
map.setPaintProperty('gdelt-events-red-pulse', 'circle-opacity', opacity)
|
||||
}
|
||||
} catch (_) {}
|
||||
} catch (_) {}
|
||||
}
|
||||
animRef.current = requestAnimationFrame(tick)
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,12 @@ export interface CombatLosses {
|
||||
missiles?: number
|
||||
helicopters?: number
|
||||
submarines?: number
|
||||
/** 坦克 */
|
||||
tanks?: number
|
||||
/** 民船 */
|
||||
civilianShips?: number
|
||||
/** 机/港(机场/港口) */
|
||||
airportPort?: number
|
||||
}
|
||||
|
||||
export interface SituationUpdate {
|
||||
@@ -161,6 +167,9 @@ export const INITIAL_MOCK_DATA: MilitarySituation = {
|
||||
missiles: 12,
|
||||
helicopters: 1,
|
||||
submarines: 0,
|
||||
tanks: 0,
|
||||
civilianShips: 0,
|
||||
airportPort: 0,
|
||||
},
|
||||
wallStreetInvestmentTrend: [
|
||||
{ time: '2025-03-01T00:00:00', value: 82 },
|
||||
@@ -215,6 +224,9 @@ export const INITIAL_MOCK_DATA: MilitarySituation = {
|
||||
missiles: 156,
|
||||
helicopters: 8,
|
||||
submarines: 2,
|
||||
tanks: 0,
|
||||
civilianShips: 0,
|
||||
airportPort: 0,
|
||||
},
|
||||
retaliationSentiment: 78,
|
||||
retaliationSentimentHistory: [
|
||||
|
||||
@@ -80,6 +80,9 @@ export function useReplaySituation(): MilitarySituation {
|
||||
missiles: lerp(0, usLoss.missiles ?? 0),
|
||||
helicopters: lerp(0, usLoss.helicopters ?? 0),
|
||||
submarines: lerp(0, usLoss.submarines ?? 0),
|
||||
tanks: lerp(0, usLoss.tanks ?? 0),
|
||||
civilianShips: lerp(0, usLoss.civilianShips ?? 0),
|
||||
airportPort: lerp(0, usLoss.airportPort ?? 0),
|
||||
}
|
||||
const irLossesAt = {
|
||||
bases: {
|
||||
@@ -99,6 +102,9 @@ export function useReplaySituation(): MilitarySituation {
|
||||
missiles: lerp(0, irLoss.missiles ?? 0),
|
||||
helicopters: lerp(0, irLoss.helicopters ?? 0),
|
||||
submarines: lerp(0, irLoss.submarines ?? 0),
|
||||
tanks: lerp(0, irLoss.tanks ?? 0),
|
||||
civilianShips: lerp(0, irLoss.civilianShips ?? 0),
|
||||
airportPort: lerp(0, irLoss.airportPort ?? 0),
|
||||
}
|
||||
|
||||
// 被袭基地:按 damage_level 排序,高损毁先出现;根据 progress 决定显示哪些为 attacked
|
||||
|
||||
Reference in New Issue
Block a user