117 lines
3.8 KiB
JavaScript
117 lines
3.8 KiB
JavaScript
import { useMapStore } from '@/stores/mapStore';
|
|
import moment from 'moment';
|
|
import { nodesMaxAge, nodesOfflineAge } from '@/config'; // TODO: use config store
|
|
import { icons } from '@/map';
|
|
import { hasNodeUplinkedToMqttRecently, isValidCoordinates } from '@/utils';
|
|
|
|
export function useNodeProcessor() {
|
|
const mapStore = useMapStore(); // Access your mapStore from Pinia
|
|
|
|
// This function processes new node data
|
|
const processNewNodes = (newNodes) => {
|
|
const now = moment();
|
|
const processedNodes = [];
|
|
const processedMarkers = {};
|
|
|
|
for (const node of newNodes) {
|
|
// Skip nodes older than configured node max age
|
|
if (nodesMaxAge.value) {
|
|
const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at));
|
|
if (lastUpdatedAgeInMillis > nodesMaxAge.value * 1000) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Compute background/text colors beforehand
|
|
node.backgroundColor = getNodeColor(node.node_id) || '#888'; // Default to '#888' if undefined
|
|
node.textColor = getNodeTextColor(node.node_id) || '#FFFFFF'; // Default to white if undefined
|
|
|
|
// Add node to the processed list regardless of its position
|
|
processedNodes.push(node);
|
|
|
|
// Skip nodes with invalid or missing position
|
|
if (!node.latitude || !node.longitude || isNaN(node.latitude) || isNaN(node.longitude)) {
|
|
continue;
|
|
}
|
|
|
|
// Fix latitude and longitude
|
|
node.latitude = node.latitude / 10000000;
|
|
node.longitude = node.longitude / 10000000;
|
|
|
|
// Icon based on MQTT connection state
|
|
let icon = icons.mqttDisconnected;
|
|
|
|
// Use offline icon for nodes older than configured node offline age
|
|
if (nodesOfflineAge.value) {
|
|
const lastUpdatedAgeInMillis = now.diff(moment(node.updated_at));
|
|
if (lastUpdatedAgeInMillis > nodesOfflineAge.value * 1000) {
|
|
icon = icons.offline;
|
|
}
|
|
}
|
|
|
|
// Check if node has uplinked to MQTT recently
|
|
if (hasNodeUplinkedToMqttRecently(node)) {
|
|
icon = icons.mqttDisconnected;
|
|
}
|
|
|
|
// Filter invalid coordinates
|
|
if (!isValidCoordinates(node.latitude, node.longitude)) {
|
|
continue;
|
|
}
|
|
|
|
// Prepare marker data
|
|
const marker = {
|
|
type: 'Feature',
|
|
properties: {
|
|
id: node.node_id,
|
|
role: node.role_name,
|
|
layer: 'nodes',
|
|
color: icon,
|
|
},
|
|
geometry: {
|
|
type: 'Point',
|
|
coordinates: [node.longitude, node.latitude],
|
|
},
|
|
};
|
|
|
|
// Add the marker to the processed markers dictionary (using node_id as the key)
|
|
processedMarkers[node.node_id] = marker;
|
|
}
|
|
|
|
// Return processed data (nodes and markers)
|
|
return { processedNodes, processedMarkers };
|
|
};
|
|
|
|
// Process new data and store it (bulk processing)
|
|
const parseNodesResponse = (newNodes) => {
|
|
const { processedNodes, processedMarkers } = processNewNodes(newNodes);
|
|
|
|
// Clear old data and update in bulk
|
|
mapStore.clearNodes();
|
|
mapStore.setNodes(processedNodes);
|
|
mapStore.setNodeMarkers(processedMarkers);
|
|
};
|
|
|
|
return {
|
|
parseNodesResponse,
|
|
};
|
|
};
|
|
|
|
|
|
// convert node id to a hex colour
|
|
function getNodeColor(nodeId) {
|
|
return "#" + (nodeId & 0x00FFFFFF).toString(16).padStart(6, '0');
|
|
};
|
|
|
|
function getNodeTextColor(nodeId) {
|
|
// extract rgb components
|
|
const r = (nodeId & 0xFF0000) >> 16;
|
|
const g = (nodeId & 0x00FF00) >> 8;
|
|
const b = nodeId & 0x0000FF;
|
|
|
|
// calculate brightness
|
|
const brightness = ((r * 0.299) + (g * 0.587) + (b * 0.114)) / 255;
|
|
|
|
// determine text color based on brightness
|
|
return brightness > 0.5 ? "#000000" : "#FFFFFF";
|
|
}; |