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"; };