diff --git a/dotbot/frontend/src/DotBots.js b/dotbot/frontend/src/DotBots.js index ec85651..2ba35e6 100644 --- a/dotbot/frontend/src/DotBots.js +++ b/dotbot/frontend/src/DotBots.js @@ -55,35 +55,35 @@ const DotBots = ({ dotbots, areaSize, updateDotbots, publishCommand, publish }) } if (dotbot.application === ApplicationType.SailBot) { - let dotbotsTmp = dotbots.slice(); - for (let idx = 0; idx < dotbots.length; idx++) { - if (dotbots[idx].address === dotbot.address) { - if (dotbotsTmp[idx].waypoints.length === 0) { - dotbotsTmp[idx].waypoints.push({ - latitude: dotbotsTmp[idx].gps_position.latitude, - longitude: dotbotsTmp[idx].gps_position.longitude, - }); - } - dotbotsTmp[idx].waypoints.push({latitude: x, longitude: y}); - updateDotbots(dotbotsTmp); + const dotbotsTmp = dotbots.map(db => { + if (db.address !== dotbot.address) return db; // unchanged refs are fine + + const newWaypoints = [...db.waypoints]; // new array, new ref + if (newWaypoints.length === 0) { + newWaypoints.push({ + latitude: db.gps_position.latitude, + longitude: db.gps_position.longitude, + }); } - } + newWaypoints.push({ latitude: x, longitude: y }); + + return { ...db, waypoints: newWaypoints }; // new object ref ✓ + }); + updateDotbots(dotbotsTmp); } if (dotbot.application === ApplicationType.DotBot) { - let dotbotsTmp = dotbots.slice(); - for (let idx = 0; idx < dotbots.length; idx++) { - if (dotbots[idx].address === dotbot.address) { - if (dotbotsTmp[idx].waypoints.length === 0) { - dotbotsTmp[idx].waypoints.push({ - x: dotbotsTmp[idx].lh2_position.x, - y: dotbotsTmp[idx].lh2_position.y, - z: 0 - }); - } - dotbotsTmp[idx].waypoints.push({x: x, y: y, z: 0}); - updateDotbots(dotbotsTmp); + const dotbotsTmp = dotbots.map(db => { + if (db.address !== dotbot.address) return db; + + const newWaypoints = [...db.waypoints]; + if (newWaypoints.length === 0) { + newWaypoints.push({ x: db.lh2_position.x, y: db.lh2_position.y, z: 0 }); } - } + newWaypoints.push({ x, y, z: 0 }); + + return { ...db, waypoints: newWaypoints }; // new object ref ✓ + }); + updateDotbots(dotbotsTmp); } }, [activeDotbot, dotbots, updateDotbots] ); diff --git a/dotbot/frontend/src/DotBotsMap.js b/dotbot/frontend/src/DotBotsMap.js index 73a4346..e601eb1 100644 --- a/dotbot/frontend/src/DotBotsMap.js +++ b/dotbot/frontend/src/DotBotsMap.js @@ -80,7 +80,7 @@ const DotBotsPosition = (props) => { ) } -const DotBotsMapPoint = (props) => { +const DotBotsMapPoint = React.memo((props) => { const [hovered, setHovered ] = useState(false); let rgbColor = "rgb(0, 0, 0)" @@ -122,7 +122,8 @@ const DotBotsMapPoint = (props) => { opacity={waypointOpacity} waypoints={props.dotbot.waypoints} threshold={props.dotbot.waypoints_threshold} - {...props} + areaSize={props.areaSize} + mapSize={props.mapSize} /> )) )} @@ -152,7 +153,7 @@ const DotBotsMapPoint = (props) => { ) -} +}) export const DotBotsMap = (props) => { @@ -197,7 +198,17 @@ export const DotBotsMap = (props) => { props.dotbots && props.dotbots .filter(dotbot => dotbot.status !== 2) .filter(dotbot => dotbot.lh2_position) - .map(dotbot => ) + .map(dotbot => ) } diff --git a/dotbot/frontend/src/QrKeyApp.js b/dotbot/frontend/src/QrKeyApp.js index 319a556..47511e8 100644 --- a/dotbot/frontend/src/QrKeyApp.js +++ b/dotbot/frontend/src/QrKeyApp.js @@ -42,62 +42,90 @@ const QrKeyApp = () => { setDotbots(dotbotsTmp); } if (payload.cmd === NotificationType.Update && dotbots && dotbots.length > 0) { - let dotbotsTmp = dotbots.slice(); - for (let idx = 0; idx < dotbots.length; idx++) { - if (dotbots[idx].address === payload.data.address) { - if (payload.data.direction !== undefined && payload.data.direction !== null) { - dotbotsTmp[idx].direction = payload.data.direction; + setDotbots(prev => { + let changed = false; + let next = prev.map(bot => { + if (bot.address !== payload.data.address) { return bot; } + + let botChanged = false; + let updated = bot; + + // direction + if (payload.data.direction != null && bot.direction !== payload.data.direction) { + updated = { ...updated, direction: payload.data.direction }; + botChanged = true; } - if (payload.data.rgb_led !== undefined) { - if (dotbotsTmp[idx].rgb_led === undefined) { - dotbotsTmp[idx].rgb_led = { - red: 0, - green: 0, - blue: 0 - } + + // rgb_led + if (payload.data.rgb_led != null) { + const newLed = payload.data.rgb_led; + const oldLed = bot.rgb_led ?? { red: 0, green: 0, blue: 0 }; + + if ( + oldLed.red !== newLed.red || + oldLed.green !== newLed.green || + oldLed.blue !== newLed.blue + ) { + updated = { ...updated, rgb_led: newLed }; + botChanged = true; } - dotbotsTmp[idx].rgb_led.red = payload.data.rgb_led.red; - dotbotsTmp[idx].rgb_led.green = payload.data.rgb_led.green; - dotbotsTmp[idx].rgb_led.blue = payload.data.rgb_led.blue; } - if (payload.data.lh2_position !== undefined && payload.data.lh2_position !== null) { - const newPosition = { - x: payload.data.lh2_position.x, - y: payload.data.lh2_position.y - }; - console.log('distance threshold:', lh2_distance_threshold, lh2_distance(dotbotsTmp[idx].lh2_position, newPosition)); - if (dotbotsTmp[idx].lh2_position && (dotbotsTmp[idx].position_history.length === 0 || lh2_distance(dotbotsTmp[idx].lh2_position, newPosition) >= lh2_distance_threshold)) { - console.log('Adding to position history'); - dotbotsTmp[idx].position_history.push(newPosition); - } - dotbotsTmp[idx].lh2_position = newPosition; + + // wind_angle + if (payload.data.wind_angle != null && bot.wind_angle !== payload.data.wind_angle) { + updated = { ...updated, wind_angle: payload.data.wind_angle }; + botChanged = true; } - if (payload.data.lh2_waypoints !== undefined) { - dotbotsTmp[idx].lh2_waypoints = payload.data.lh2_waypoints; + + // rudder_angle + if (payload.data.rudder_angle != null && bot.rudder_angle !== payload.data.rudder_angle) { + updated = { ...updated, rudder_angle: payload.data.rudder_angle }; + botChanged = true; } - if (payload.data.gps_position !== undefined && payload.data.gps_position !== null) { - const newPosition = { - latitude: payload.data.gps_position.latitude, - longitude: payload.data.gps_position.longitude - }; - if (dotbotsTmp[idx].gps_position !== undefined && dotbotsTmp[idx].gps_position !== null && (dotbotsTmp[idx].position_history.length === 0 || gps_distance(dotbotsTmp[idx].gps_position, newPosition) > gps_distance_threshold)) { - dotbotsTmp[idx].position_history.push(newPosition); - } - dotbotsTmp[idx].gps_position = newPosition; + + // sail_angle + if (payload.data.sail_angle != null && bot.sail_angle !== payload.data.sail_angle) { + updated = { ...updated, sail_angle: payload.data.sail_angle }; + botChanged = true; } - if (payload.data.gps_waypoints !== undefined) { - dotbotsTmp[idx].gps_waypoints = payload.data.gps_waypoints; + + // lh2_position + position_history + if (payload.data.lh2_position != null && lh2_distance(bot.lh2_position, payload.data.lh2_position) > lh2_distance_threshold) { + let newHistory = [...bot.position_history, payload.data.lh2_position]; + updated = { ...updated, lh2_position: payload.data.lh2_position, position_history: newHistory }; + botChanged = true; } - if (payload.data.position_history !== undefined) { - dotbotsTmp[idx].position_history = payload.data.position_history; + + // lh2_waypoints + if (payload.data.lh2_waypoints != null) { + updated = { ...updated, lh2_waypoints: payload.data.lh2_waypoints }; + botChanged = true; } - if (payload.data.battery !== undefined) { - dotbotsTmp[idx].battery = payload.data.battery ; + + // gps_position + position_history + if (payload.data.gps_position != null && gps_distance(bot.gps_position, payload.data.gps_position) > gps_distance_threshold) { + let newHistory = [...bot.position_history, payload.data.gps_position]; + updated = { ...updated, gps_position: payload.data.gps_position, position_history: newHistory }; + botChanged = true; } - setDotbots(dotbotsTmp); - break; - } - } + + // gps_waypoints + if (payload.data.gps_waypoints != null) { + updated = { ...updated, gps_waypoints: payload.data.gps_waypoints }; + botChanged = true; + } + + // battery + if (payload.data.battery != null && Math.abs(bot.battery - payload.data.battery) > 0.1) { + updated = { ...updated, battery: payload.data.battery }; + botChanged = true; + } + + if (botChanged) {changed = true;} + return botChanged ? updated : bot; + }); + return changed ? next : prev; + }); } else if (payload.cmd === NotificationType.Reload) { log.info("Reload notification"); sendRequest({request: RequestType.DotBots, reply: `${clientId}`}); diff --git a/dotbot/frontend/src/RestApp.js b/dotbot/frontend/src/RestApp.js index e164576..90b2cb9 100644 --- a/dotbot/frontend/src/RestApp.js +++ b/dotbot/frontend/src/RestApp.js @@ -60,69 +60,90 @@ const RestApp = () => { setDotbots(dotbotsTmp); } if (message.cmd === NotificationType.Update && dotbots && dotbots.length > 0) { - let dotbotsTmp = dotbots.slice(); - for (let idx = 0; idx < dotbots.length; idx++) { - if (dotbots[idx].address === message.data.address) { - if (message.data.direction !== undefined && message.data.direction !== null) { - dotbotsTmp[idx].direction = message.data.direction; + setDotbots(prev => { + let changed = false; + let next = prev.map(bot => { + if (bot.address !== message.data.address) { return bot; } + + let botChanged = false; + let updated = bot; + + // direction + if (message.data.direction != null && bot.direction !== message.data.direction) { + updated = { ...updated, direction: message.data.direction }; + botChanged = true; } - if (message.data.rgb_led !== undefined) { - if (dotbotsTmp[idx].rgb_led === undefined) { - dotbotsTmp[idx].rgb_led = { - red: 0, - green: 0, - blue: 0 - } + + // rgb_led + if (message.data.rgb_led != null) { + const newLed = message.data.rgb_led; + const oldLed = bot.rgb_led ?? { red: 0, green: 0, blue: 0 }; + + if ( + oldLed.red !== newLed.red || + oldLed.green !== newLed.green || + oldLed.blue !== newLed.blue + ) { + updated = { ...updated, rgb_led: newLed }; + botChanged = true; } - dotbotsTmp[idx].rgb_led.red = message.data.rgb_led.red; - dotbotsTmp[idx].rgb_led.green = message.data.rgb_led.green; - dotbotsTmp[idx].rgb_led.blue = message.data.rgb_led.blue; } - if (message.data.wind_angle !== undefined && message.data.wind_angle !== null) { - dotbotsTmp[idx].wind_angle = message.data.wind_angle; - } - if (message.data.rudder_angle !== undefined && message.data.rudder_angle !== null) { - dotbotsTmp[idx].rudder_angle = message.data.rudder_angle; + + // wind_angle + if (message.data.wind_angle != null && bot.wind_angle !== message.data.wind_angle) { + updated = { ...updated, wind_angle: message.data.wind_angle }; + botChanged = true; } - if (message.data.sail_angle !== undefined && message.data.sail_angle !== null) { - dotbotsTmp[idx].sail_angle = message.data.sail_angle; + + // rudder_angle + if (message.data.rudder_angle != null && bot.rudder_angle !== message.data.rudder_angle) { + updated = { ...updated, rudder_angle: message.data.rudder_angle }; + botChanged = true; } - if (message.data.lh2_position !== undefined && message.data.lh2_position !== null) { - const newPosition = { - x: message.data.lh2_position.x, - y: message.data.lh2_position.y - }; - if (dotbotsTmp[idx].lh2_position !== undefined && dotbotsTmp[idx].lh2_position !== null && (dotbotsTmp[idx].position_history.length === 0 || lh2_distance(dotbotsTmp[idx].lh2_position, newPosition) > lh2_distance_threshold)) { - dotbotsTmp[idx].position_history.push(newPosition); - } - dotbotsTmp[idx].lh2_position = newPosition; + + // sail_angle + if (message.data.sail_angle != null && bot.sail_angle !== message.data.sail_angle) { + updated = { ...updated, sail_angle: message.data.sail_angle }; + botChanged = true; } - if (message.data.lh2_waypoints !== undefined) { - dotbotsTmp[idx].lh2_waypoints = message.data.lh2_waypoints; + + // lh2_position + position_history + if (message.data.lh2_position != null && lh2_distance(bot.lh2_position, message.data.lh2_position) > lh2_distance_threshold) { + let newHistory = [...bot.position_history, message.data.lh2_position]; + updated = { ...updated, lh2_position: message.data.lh2_position, position_history: newHistory }; + botChanged = true; } - if (message.data.gps_position !== undefined && message.data.gps_position !== null) { - const newPosition = { - latitude: message.data.gps_position.latitude, - longitude: message.data.gps_position.longitude - }; - if (dotbotsTmp[idx].gps_position !== undefined && dotbotsTmp[idx].gps_position !== null && (dotbotsTmp[idx].position_history.length === 0 || gps_distance(dotbotsTmp[idx].gps_position, newPosition) > gps_distance_threshold)) { - dotbotsTmp[idx].position_history.push(newPosition); - } - dotbotsTmp[idx].gps_position = newPosition; + + // lh2_waypoints + if (message.data.lh2_waypoints != null) { + updated = { ...updated, lh2_waypoints: message.data.lh2_waypoints }; + botChanged = true; } - if (message.data.gps_waypoints !== undefined) { - dotbotsTmp[idx].gps_waypoints = message.data.gps_waypoints; + + // gps_position + position_history + if (message.data.gps_position != null && gps_distance(bot.gps_position, message.data.gps_position) > gps_distance_threshold) { + let newHistory = [...bot.position_history, message.data.gps_position]; + updated = { ...updated, gps_position: message.data.gps_position, position_history: newHistory }; + botChanged = true; } - if (message.data.position_history !== undefined) { - dotbotsTmp[idx].position_history = message.data.position_history; + + // gps_waypoints + if (message.data.gps_waypoints != null) { + updated = { ...updated, gps_waypoints: message.data.gps_waypoints }; + botChanged = true; } - if (message.data.battery !== undefined) { - dotbotsTmp[idx].battery = message.data.battery; + + // battery + if (message.data.battery != null && Math.abs(bot.battery - message.data.battery) > 0.1) { + updated = { ...updated, battery: message.data.battery }; + botChanged = true; } - setDotbots(dotbotsTmp); - break; - } - } + + if (botChanged) {changed = true;} + return botChanged ? updated : bot; + }); + return changed ? next : prev; + }); } };