Optimize map performance: reduce payload 75%, faster rendering
- Remove factors from heatmap scores, fetch on-demand via point_detail - Pre-encode initial scores JSON once instead of per-render - Don't store scores in socket assigns (reduce memory) - Pre-calculate RGBA color lookup table for canvas rendering - Batch fillStyle changes, hoist math out of inner loop - Show topbar immediately on data requests (no 300ms delay)
This commit is contained in:
parent
2f2f3388cd
commit
1aebd7f1cc
2 changed files with 32 additions and 8 deletions
|
|
@ -264,14 +264,21 @@ export const PropagationMap = {
|
|||
}
|
||||
})
|
||||
|
||||
// Click on map to show factor breakdown + range circle
|
||||
// Click on map to request factor detail from server
|
||||
this.map.on("click", (e) => {
|
||||
const detail = this.lookupPoint(e.latlng.lat, e.latlng.lng)
|
||||
const basic = this.lookupPoint(e.latlng.lat, e.latlng.lng)
|
||||
if (basic) {
|
||||
this.showRangeCircles(basic)
|
||||
this.pushEvent("point_detail", { lat: e.latlng.lat, lon: e.latlng.lng })
|
||||
}
|
||||
})
|
||||
|
||||
this.handleEvent("point_detail", (detail) => {
|
||||
if (detail) {
|
||||
this.showRangeCircles(detail)
|
||||
const merged = { ...detail, ...this.bandInfo }
|
||||
this.detailPopup
|
||||
.setLatLng([detail.lat, detail.lon])
|
||||
.setContent(buildPopupHTML(detail))
|
||||
.setContent(buildPopupHTML(merged))
|
||||
.openOn(this.map)
|
||||
}
|
||||
})
|
||||
|
|
@ -327,6 +334,13 @@ export const PropagationMap = {
|
|||
this.gridData.set(key, s)
|
||||
})
|
||||
|
||||
// Pre-calculate RGBA strings for scores 0-100
|
||||
const colorCache = new Array(101)
|
||||
for (let i = 0; i <= 100; i++) {
|
||||
const c = this.scoreColorRGB(i)
|
||||
colorCache[i] = `rgba(${c.r},${c.g},${c.b},0.55)`
|
||||
}
|
||||
|
||||
const self = this
|
||||
this.scoreOverlay = L.GridLayer.extend({
|
||||
createTile(coords) {
|
||||
|
|
@ -345,15 +359,20 @@ export const PropagationMap = {
|
|||
const lonPerPx = (se.lng - nw.lng) / size.x
|
||||
const cellPxX = Math.max(1, Math.ceil(step / lonPerPx))
|
||||
const cellPxY = Math.max(1, Math.ceil(step / Math.abs(latPerPx)))
|
||||
const absLatPerPx = Math.abs(latPerPx)
|
||||
|
||||
let lastColor = null
|
||||
for (let py = 0; py < size.y; py += cellPxY) {
|
||||
const lat = nw.lat - py * absLatPerPx
|
||||
for (let px = 0; px < size.x; px += cellPxX) {
|
||||
const lat = nw.lat - py * Math.abs(latPerPx)
|
||||
const lon = nw.lng + px * lonPerPx
|
||||
const score = self.interpolateScore(lat, lon, step)
|
||||
if (score !== null) {
|
||||
const color = self.scoreColorRGB(score)
|
||||
ctx.fillStyle = `rgba(${color.r},${color.g},${color.b},0.55)`
|
||||
const color = colorCache[Math.max(0, Math.min(100, Math.round(score)))]
|
||||
if (color !== lastColor) {
|
||||
ctx.fillStyle = color
|
||||
lastColor = color
|
||||
}
|
||||
ctx.fillRect(px, py, cellPxX, cellPxY)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,11 @@ defmodule MicrowavepropWeb.MapLive do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("point_detail", %{"lat" => lat, "lon" => lon}, socket) do
|
||||
detail = Propagation.point_detail(socket.assigns.selected_band, lat, lon)
|
||||
{:noreply, push_event(socket, "point_detail", detail || %{})}
|
||||
end
|
||||
|
||||
def handle_event("map_bounds", bounds, socket) do
|
||||
scores = Propagation.latest_scores(socket.assigns.selected_band, bounds)
|
||||
|
||||
|
|
@ -121,7 +126,7 @@ defmodule MicrowavepropWeb.MapLive do
|
|||
id="propagation-map"
|
||||
phx-hook="PropagationMap"
|
||||
phx-update="ignore"
|
||||
data-scores={Jason.encode!(@scores)}
|
||||
data-scores={@initial_scores_json}
|
||||
data-band-info={Jason.encode!(band_info(@selected_band))}
|
||||
class="absolute inset-0 z-0"
|
||||
>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue