Open gxomalis opened 4 months ago
Hey glad you like it, I think you could achieve that by modifying the persistent.js module (or here for ros2).
Initially if there's no saved layout it'll set itself to a blank-ish setup manually, but you could instead have it run this.fromJSON
on a JSON string of that layout you've got.
Simplest edit would be to just embed it as a string def like so (it might need a JSON.parse between the string and fromJSON, I haven't tested it):
const defaultString = "{\"navbar\":[{\"type\":\"settings\",\"id\":\"settings_default\"},{\"type\":\"rosbridge\",\"id\":\"rosbridge_default\"},{\"type\":\"grid\",\"id\":\"grid_default\"},{\"type\":\"tf\",\"id\":\"tf_default\"},{\"type\":\"map\",\"id\":\"map_autoID_0\"},{\"type\":\"simplegoal\",\"id\":\"simplegoal_autoID_1\"},{\"type\":\"path\",\"id\":\"path_autoID_2\"},{\"type\":\"teleop\",\"id\":\"teleop_autoID_4\"},{\"type\":\"scan\",\"id\":\"scan_autoID_5\"},{\"type\":\"robotmodel\",\"id\":\"robotmodel_autoID_6\"}],\"view\":{\"center\":{\"x\":2.705681638721338,\"y\":0.5385767082942933},\"scale\":46.10223738657773},\"grid_default\":{\"size\":1,\"thickness\":1,\"colour\":\"#3e556a\"},\"tf_default\":{\"show_names\":true,\"show_axes\":true,\"show_lines\":true,\"scale\":1,\"frame_visibility\":{\"base_link\":true,\"odom\":true,\"lower\":true,\"LDS-01\":true,\"solid\":true,\"leftwheel\":true,\"rightwheel\":true,\"map\":true,\"base_footprint\":true,\"screw0\":true,\"screw1\":true,\"screw2\":true,\"screw3\":true,\"accelerometer\":true,\"compass\":true,\"gps\":true,\"gyro\":true,\"imu_link\":true,\"inertial_unit\":true,\"wheel_left_link\":true,\"wheel_right_link\":true,\"camera_link\":true,\"camera_rgb_frame\":true,\"camera_rgb_optical_frame\":true,\"caster_back_left_link\":true,\"caster_back_right_link\":true,\"base_scan\":true}},\"settings_default\":{\"fixed_frame\":\"map\",\"background_color\":\"#273444\"},\"uid\":15,\"map_autoID_0\":{\"topic\":\"/map\",\"opacity\":\"0.65\",\"costmap_mode\":false,\"throttle\":\"1000\",\"use_timestamp\":false},\"simplegoal_autoID_1\":{\"topic\":\"/goal_pose\"},\"path_autoID_2\":{\"topic\":\"/local_plan\",\"color\":\"#15ff00\"},\"posewithcovariancestamped_autoID_3\":{\"topic\":\"/amcl_pose\",\"scale\":1},\"teleop_autoID_4\":{\"topic\":\"/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"87.26287262872629%\",\"joy_offset_y\":\"84%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"path_autoID_5\":{\"topic\":\"/local_plan\",\"color\":\"#5ed753\"},\"waypoints_autoID_6\":{\"topic\":\"/plan\",\"fixed_frame\":\"\",\"points\":[],\"start_closest\":true},\"path_autoID_7\":{\"topic\":\"/plan\",\"color\":\"#5ed753\"},\"path_autoID_8\":{\"topic\":\"/plan\",\"color\":\"#5ed753\"},\"path_autoID_9\":{\"topic\":\"/plan_smoothed\",\"color\":\"#5ed753\"},\"path_autoID_10\":{\"topic\":\"/received_global_plan\",\"color\":\"#5ed753\"},\"path_autoID_11\":{\"topic\":\"/transformed_global_plan\",\"color\":\"#5ed753\"},\"path_autoID_12\":{\"topic\":\"/plan\",\"color\":\"#5ed753\"},\"waypoints_autoID_13\":{\"topic\":\"/plan\",\"fixed_frame\":\"map\",\"points\":[],\"start_closest\":true},\"map_autoID_14\":{\"topic\":\"/map\",\"opacity\":\"0.7\",\"costmap_mode\":false,\"throttle\":\"1000\",\"use_timestamp\":false},\"path_autoID_15\":{\"topic\":\"/local_plan\",\"color\":\"#5ed753\"},\"scan_autoID_5\":{\"topic\":\"/scan\",\"opacity\":\"0.5\",\"thickness\":\"0.07\",\"color\":\"#ff1100\",\"throttle\":\"2000\"},\"robotmodel_autoID_6\":{\"frame\":\"base_link\",\"sprite\":\"pancake\",\"length\":\"0.5\"},\"simplegoal_autoID_7\":{\"topic\":\"/goal_pose\"},\"button_autoID_8\":{\"topic\":\"\",\"text\":\"Text\",\"typedict\":{}},\"teleop_autoID_9\":{\"topic\":\"/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"initialpose_autoID_10\":{\"topic\":\"/initialpose\"},\"robotmodel_autoID_7\":{\"frame\":\"base_link\",\"sprite\":\"4wd\",\"length\":\"0.5\"},\"robotmodel_autoID_8\":{\"frame\":\"base_link\",\"sprite\":\"4wd\",\"length\":\"0.5\"},\"tf_autoID_9\":{\"show_names\":true,\"show_axes\":true,\"show_lines\":true,\"scale\":1,\"frame_visibility\":{}},\"teleop_autoID_10\":{\"topic\":\"/turtle1/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"83.33333333333334%\",\"joy_offset_y\":\"85.16666666666667%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"teleop_autoID_11\":{\"topic\":\"/turtle1/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"teleop_autoID_12\":{\"topic\":\"/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"teleop_autoID_13\":{\"topic\":\"/turtle1/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"markerarray_autoID_14\":{\"topic\":\"/marker\"}}";
...
if (localStorage.hasOwnProperty("settings")) {
this.fromJSON(localStorage.getItem("settings"));
}else{
this.fromJSON(defaultString);
}
A more proper solution for future use would be to have a default json in the asset folder and have the server send it over, that way we could just simply swap the file and be done with it, or even have the server check for extra files that override the default without replacing it so it wouldn't cause any git conflicts...
I'll see if I can add that sometime soon, it ought to to come in handy.
Hey! Big thanks for your quick reply. Hm okay I'm a newbie in the Linux world and everything so please bare with me. Here's what I did now. I'm using the ros2 version of Vizanti.
I found persistent.js in /vizanti/vizanti_server/public/js/modules
I changed the constructor to this:
constructor() {
const defaultString = "{\"navbar\":[{\"type\":\"settings\",\"id\":\"settings_default\"},{\"type\":\"rosbridge\",\"id\":\"rosbridge_default\"},{\"type\":\"grid\",\"id\":\"grid_default\"},{\"type\":\"tf\",\"id\":\"tf_default\"},{\"type\":\"map\",\"id\":\"map_autoID_0\"},{\"type\":\"simplegoal\",\"id\":\"simplegoal_autoID_1\"},{\"type\":\"path\",\"id\":\"path_autoID_2\"},{\"type\":\"teleop\",\"id\":\"teleop_autoID_4\"},{\"type\":\"scan\",\"id\":\"scan_autoID_5\"},{\"type\":\"robotmodel\",\"id\":\"robotmodel_autoID_6\"}],\"view\":{\"center\":{\"x\":2.705681638721338,\"y\":0.5385767082942933},\"scale\":46.10223738657773},\"grid_default\":{\"size\":1,\"thickness\":1,\"colour\":\"#3e556a\"},\"tf_default\":{\"show_names\":true,\"show_axes\":true,\"show_lines\":true,\"scale\":1,\"frame_visibility\":{\"base_link\":true,\"odom\":true,\"lower\":true,\"LDS-01\":true,\"solid\":true,\"leftwheel\":true,\"rightwheel\":true,\"map\":true,\"base_footprint\":true,\"screw0\":true,\"screw1\":true,\"screw2\":true,\"screw3\":true,\"accelerometer\":true,\"compass\":true,\"gps\":true,\"gyro\":true,\"imu_link\":true,\"inertial_unit\":true,\"wheel_left_link\":true,\"wheel_right_link\":true,\"camera_link\":true,\"camera_rgb_frame\":true,\"camera_rgb_optical_frame\":true,\"caster_back_left_link\":true,\"caster_back_right_link\":true,\"base_scan\":true}},\"settings_default\":{\"fixed_frame\":\"map\",\"background_color\":\"#273444\"},\"uid\":15,\"map_autoID_0\":{\"topic\":\"/map\",\"opacity\":\"0.65\",\"costmap_mode\":false,\"throttle\":\"1000\",\"use_timestamp\":false},\"simplegoal_autoID_1\":{\"topic\":\"/goal_pose\"},\"path_autoID_2\":{\"topic\":\"/local_plan\",\"color\":\"#15ff00\"},\"posewithcovariancestamped_autoID_3\":{\"topic\":\"/amcl_pose\",\"scale\":1},\"teleop_autoID_4\":{\"topic\":\"/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"87.26287262872629%\",\"joy_offset_y\":\"84%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"path_autoID_5\":{\"topic\":\"/local_plan\",\"color\":\"#5ed753\"},\"waypoints_autoID_6\":{\"topic\":\"/plan\",\"fixed_frame\":\"\",\"points\":[],\"start_closest\":true},\"path_autoID_7\":{\"topic\":\"/plan\",\"color\":\"#5ed753\"},\"path_autoID_8\":{\"topic\":\"/plan\",\"color\":\"#5ed753\"},\"path_autoID_9\":{\"topic\":\"/plan_smoothed\",\"color\":\"#5ed753\"},\"path_autoID_10\":{\"topic\":\"/received_global_plan\",\"color\":\"#5ed753\"},\"path_autoID_11\":{\"topic\":\"/transformed_global_plan\",\"color\":\"#5ed753\"},\"path_autoID_12\":{\"topic\":\"/plan\",\"color\":\"#5ed753\"},\"waypoints_autoID_13\":{\"topic\":\"/plan\",\"fixed_frame\":\"map\",\"points\":[],\"start_closest\":true},\"map_autoID_14\":{\"topic\":\"/map\",\"opacity\":\"0.7\",\"costmap_mode\":false,\"throttle\":\"1000\",\"use_timestamp\":false},\"path_autoID_15\":{\"topic\":\"/local_plan\",\"color\":\"#5ed753\"},\"scan_autoID_5\":{\"topic\":\"/scan\",\"opacity\":\"0.5\",\"thickness\":\"0.07\",\"color\":\"#ff1100\",\"throttle\":\"2000\"},\"robotmodel_autoID_6\":{\"frame\":\"base_link\",\"sprite\":\"pancake\",\"length\":\"0.5\"},\"simplegoal_autoID_7\":{\"topic\":\"/goal_pose\"},\"button_autoID_8\":{\"topic\":\"\",\"text\":\"Text\",\"typedict\":{}},\"teleop_autoID_9\":{\"topic\":\"/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"initialpose_autoID_10\":{\"topic\":\"/initialpose\"},\"robotmodel_autoID_7\":{\"frame\":\"base_link\",\"sprite\":\"4wd\",\"length\":\"0.5\"},\"robotmodel_autoID_8\":{\"frame\":\"base_link\",\"sprite\":\"4wd\",\"length\":\"0.5\"},\"tf_autoID_9\":{\"show_names\":true,\"show_axes\":true,\"show_lines\":true,\"scale\":1,\"frame_visibility\":{}},\"teleop_autoID_10\":{\"topic\":\"/turtle1/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"83.33333333333334%\",\"joy_offset_y\":\"85.16666666666667%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"teleop_autoID_11\":{\"topic\":\"/turtle1/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"teleop_autoID_12\":{\"topic\":\"/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"teleop_autoID_13\":{\"topic\":\"/turtle1/cmd_vel\",\"linear_velocity\":0.4,\"angular_velocity\":0.8,\"joy_offset_x\":\"50%\",\"joy_offset_y\":\"85%\",\"accel\":0.05,\"invert_angular\":true,\"holonomic_swap\":false},\"markerarray_autoID_14\":{\"topic\":\"/marker\"}}";
if (localStorage.hasOwnProperty("settings")) {
this.fromJSON(localStorage.getItem("settings"));
}else{
this.fromJSON(defaultString);
}
}
I save the file, rebuild vizanti and then I run it.
I cleared cookies and history on my browser, I visit localhost:5000 and it's the same as before.
Am I missing something or am I doing something wrong?
Hmm that sounds like that should work. It might be that the cookie deletion didn't include local storage, since these aren't technically cookies. Does it do the same in an incognito window?
You can check what's being saved by opening F12 -> Storage -> Local Storage, then there might still be a key labelled "settings" and you can delete it manually.
Yes same in incognito and after deleting storage manually...
I've given your exact code a test run on my end and I seem to get the defaults loaded right. Triggering "reset layout to default" in global settings also sets it to the new json as it should.
Maybe there's something with colcon not copying files over correctly, it shouldn't happen typically but it might be worth trying a fresh rebuild in case it's ignoring the file changes.
Okay it worked! I rebuilt it from scratch and it works very good. Big big thanks! One more thing and I will close the issue, how did you turn the layout.json file I included in the defaultString you provided?
Ah glad it works :+1:
I just threw it into https://jsontostring.com, and let's actually leave it open for the time being. I could use a reminder to implement this properly with file swapping.
Perfect. Big thanks again for the help!
Hey @gxomalis, I've finally gotten around to implementing this properly, you can check out the implementation in PR #75 for Humble or #76 for Noetic. The general idea is that you can specify a path in the launch file which points to an exported json and it'll use it as the default.
It seems to work reliably on my end, but it would be a great help if you could give it a quick test if you're still using this makeshift setup.
Hey @MoffKalast , I will look into it as soon as I can! Thanks for taking the time and making this happen! I'll let you know when I test it.
Hello @MoffKalast
Vizanti has been a great tool for the project I'm working on. I have setup the layout the way I want with the widgets I need, but if I open Vizanti on a new browser, the layout goes back to the default one and I have to load my layout file or re-add the widgets.
How can I change the Default Layout to the one I want to use, so it loads automatically the widgets I want when I'm on a new browser?
Here's the layout I'm using now: robot_config.json