Meta Description" name="description" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Maptalks Track Layer Performance Benchmark</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maptalks/dist/maptalks.css">
<script src="https://cdn.jsdelivr.net/npm/maptalks/dist/maptalks.min.js"></script>
<style>
body { margin: 0; padding: 0; font-family: 'Segoe UI', sans-serif; overflow: hidden; }
#map { width: 100vw; height: 100vh; }
/* Control Panel */
.controls {
position: absolute;
top: 20px;
left: 20px;
background: rgba(20, 20, 20, 0.9);
color: white;
padding: 15px;
border-radius: 8px;
z-index: 100;
width: 280px;
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
}
h3 { margin: 0 0 10px 0; border-bottom: 1px solid #555; padding-bottom: 5px; }
.btn-group { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 15px; }
button {
flex: 1 0 30%;
padding: 8px;
background: #333;
border: 1px solid #555;
color: white;
cursor: pointer;
border-radius: 4px;
font-weight: bold;
}
button:hover { background: #444; }
button.active { background: #0078d4; border-color: #0078d4; }
/* Stats Panel */
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
font-size: 13px;
}
.stat-item { background: #333; padding: 5px; border-radius: 4px; }
.stat-label { color: #aaa; font-size: 11px; }
.stat-value { font-size: 16px; font-weight: bold; color: #4caf50; }
.warning { color: #ff5252; }
</style>
</head>
<body>
<div id="map"></div>
<div class="controls">
<h3>π Track Benchmark</h3>
<div class="stat-label" style="margin-bottom:5px">Pilih Jumlah Object:</div>
<div class="btn-group">
<button onclick="runScenario(10)">10</button>
<button onclick="runScenario(500)">500</button>
<button onclick="runScenario(1000)">1K</button>
<button onclick="runScenario(5000)">5K</button>
<button onclick="runScenario(10000)" style="color:#ff9999">10K</button>
</div>
<h3>π Metrics</h3>
<div class="stats-grid">
<div class="stat-item">
<div class="stat-label">FPS</div>
<div class="stat-value" id="fps-display">0</div>
</div>
<div class="stat-item">
<div class="stat-label">Object Count</div>
<div class="stat-value" id="count-display">0</div>
</div>
<div class="stat-item" style="grid-column: span 2;">
<div class="stat-label">Update Processing Time (CPU)</div>
<div class="stat-value" id="cpu-time-display">0 ms</div>
</div>
<div class="stat-item" style="grid-column: span 2;">
<div class="stat-label">Memory Estimate</div>
<div class="stat-value" id="mem-display">-</div>
</div>
</div>
<p style="font-size:11px; color:#888; margin-top:10px;">
*Update posisi setiap 1 detik.<br>
*10K mungkin menyebabkan freeze.
</p>
</div>
<script>
// 1. Inisialisasi Map
const map = new maptalks.Map('map', {
center: [107.6191, -6.9175], // Bandung
zoom: 13,
baseLayer: new maptalks.TileLayer('base', {
urlTemplate: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
subdomains: ['a','b','c','d'],
attribution: '© OpenStreetMap © CARTO'
})
});
// Layer untuk menampung Track
let trackLayer = new maptalks.VectorLayer('vector-tracks', [], {
enableAltitude: false, // Performance Optimization
drawImmediate: false
}).addTo(map);
// State Global
let tracks = []; // Menyimpan referensi object {marker, line, data}
let isRunning = false;
let updateInterval;
// --- 2. Performance Monitoring Class ---
const monitor = {
frameCount: 0,
lastTime: performance.now(),
start: function() {
this.loop();
},
loop: function() {
const now = performance.now();
this.frameCount++;
if (now >= this.lastTime + 1000) {
// Update FPS Display
const fps = this.frameCount;
const el = document.getElementById('fps-display');
el.innerText = fps;
el.className = fps < 30 ? 'stat-value warning' : 'stat-value';
// Update Memory (Chrome only)
if (performance.memory) {
const used = Math.round(performance.memory.usedJSHeapSize / 1048576);
document.getElementById('mem-display').innerText = used + " MB";
}
this.frameCount = 0;
this.lastTime = now;
}
requestAnimationFrame(() => this.loop());
}
};
monitor.start();
// --- 3. Scenario Logic ---
function runScenario(count) {
// Reset
stopScenario();
trackLayer.clear();
tracks = [];
document.getElementById('count-display').innerText = count;
// Generate Data Awal
console.log(`Generating ${count} tracks...`);
const center = map.getCenter();
// Batch add geometry untuk performa lebih baik saat inisialisasi
const geometries = [];
for (let i = 0; i < count; i++) {
// Random posisi sekitar center
const lng = center.x + (Math.random() - 0.5) * 0.1;
const lat = center.y + (Math.random() - 0.5) * 0.1;
// 1. Create Marker (Icon + Label)
const marker = new maptalks.Marker([lng, lat], {
symbol: {
'markerType': 'ellipse',
'markerFill': '#0078d4',
'markerWidth': 10,
'markerHeight': 10,
'textName': `ID-${i}`,
'textSize': 10,
'textDy': -15,
'textFill': '#fff'
}
});
// 2. Create Trail (Line) - Awalnya titik kosong
const line = new maptalks.LineString([[lng, lat], [lng, lat]], {
symbol: {
'lineColor': '#0078d4',
'lineWidth': 2,
'lineOpacity': 0.5
}
});
// Simpan referensi untuk update nanti
tracks.push({
id: i,
marker: marker,
line: line,
lng: lng,
lat: lat,
// Random arah pergerakan
velLng: (Math.random() - 0.5) * 0.0005,
velLat: (Math.random() - 0.5) * 0.0005
});
geometries.push(line, marker);
}
// Add to Layer
trackLayer.addGeometry(geometries);
// Start Update Loop
startUpdateLoop();
}
function stopScenario() {
if (updateInterval) clearInterval(updateInterval);
}
function startUpdateLoop() {
// Loop setiap 1 detik (1000ms) sesuai requirement
updateInterval = setInterval(() => {
const startCPU = performance.now();
// --- LOGIC UPDATE POSISI ---
// Ini adalah bagian terberat: Looping ribuan object di JavaScript
// Kita update geometry batching agar render tidak dipanggil berulang kali
// Namun di maptalks standard, kita update coord satu per satu
tracks.forEach(track => {
// 1. Hitung posisi baru
track.lng += track.velLng;
track.lat += track.velLat;
const newCoord = [track.lng, track.lat];
// 2. Update Marker
track.marker.setCoordinates(newCoord);
// 3. Update Trail (Ambil coordinate lama, tambah baru, potong kalau kepanjangan)
// Untuk performa demo ini, kita hanya buat trail sederhana (Last pos -> New Pos)
// Agar memori tidak bocor (LineString yang terus memanjang sangat berat)
const prevCoords = track.line.getCoordinates();
const nextLineCoords = [prevCoords[1], newCoord]; // Geser
track.line.setCoordinates(nextLineCoords);
});
const endCPU = performance.now();
const duration = (endCPU - startCPU).toFixed(2);
// Update Stats CPU
const cpuEl = document.getElementById('cpu-time-display');
cpuEl.innerText = duration + " ms";
// Warna merah jika proses logic memakan waktu > 50ms (bikin lag UI)
cpuEl.style.color = duration > 50 ? '#ff5252' : '#4caf50';
}, 1000);
}
</script>
</body>
</html>60
7
889KB
1317KB
820.0ms
824.0ms
1,822.0ms