diff options
| author | diogo464 <[email protected]> | 2024-10-02 09:49:46 +0100 |
|---|---|---|
| committer | diogo464 <[email protected]> | 2024-10-02 09:49:46 +0100 |
| commit | 4b096ed372253cc791be4c2404b900c8270acddc (patch) | |
| tree | 6bcfd0c5bc4fddd0f291f937270a6ac72ad5aec7 /content/static | |
| parent | d89fc43a15e639f8766a41c77b24cc281b501164 (diff) | |
improved ui
Diffstat (limited to 'content/static')
| -rw-r--r-- | content/static/main.js | 67 |
1 files changed, 43 insertions, 24 deletions
diff --git a/content/static/main.js b/content/static/main.js index 5da3b24..f2c8373 100644 --- a/content/static/main.js +++ b/content/static/main.js | |||
| @@ -4,6 +4,7 @@ const DEFAULT_COORDINATES = [38.59104623572979, -9.130882470026634]; | |||
| 4 | const ELEM_ID_MAP = "map"; | 4 | const ELEM_ID_MAP = "map"; |
| 5 | const ELEM_ID_BTN_SHAPE_CREATE = "shape-create"; | 5 | const ELEM_ID_BTN_SHAPE_CREATE = "shape-create"; |
| 6 | const ELEM_ID_BTN_SHAPE_DELETE = "shape-delete"; | 6 | const ELEM_ID_BTN_SHAPE_DELETE = "shape-delete"; |
| 7 | const ELEM_ID_BTN_SHAPE_DELETE_VERTEX = "shape-delete-vertex"; | ||
| 7 | const ELEM_ID_BTN_SHAPE_BURNED = "shape-kind-burned"; | 8 | const ELEM_ID_BTN_SHAPE_BURNED = "shape-kind-burned"; |
| 8 | const ELEM_ID_BTN_SHAPE_UNBURNED = "shape-kind-unburned"; | 9 | const ELEM_ID_BTN_SHAPE_UNBURNED = "shape-kind-unburned"; |
| 9 | const ELEM_ID_BTN_SHAPES_UPDATE = "shapes-update"; | 10 | const ELEM_ID_BTN_SHAPES_UPDATE = "shapes-update"; |
| @@ -40,8 +41,7 @@ const SHAPE_KIND_BURNED = "burned"; | |||
| 40 | * @typedef {Object} Shape | 41 | * @typedef {Object} Shape |
| 41 | * @property {string} kind | 42 | * @property {string} kind |
| 42 | * @property {[]ShapePoint} points | 43 | * @property {[]ShapePoint} points |
| 43 | * @property {Object} poly - leaflet polygon, null if points.length < 3 | 44 | * @property {[]Object} layers - leaflet layers |
| 44 | * @property {[]Object} poly_points - leaflet circles for each point | ||
| 45 | * @property {number} point_insert_idx - index to start inserting points | 45 | * @property {number} point_insert_idx - index to start inserting points |
| 46 | */ | 46 | */ |
| 47 | 47 | ||
| @@ -130,8 +130,7 @@ function lib_shape_create_empty() { | |||
| 130 | return { | 130 | return { |
| 131 | kind: SHAPE_KIND_UNBURNED, | 131 | kind: SHAPE_KIND_UNBURNED, |
| 132 | points: [], | 132 | points: [], |
| 133 | poly: null, | 133 | layers: [], |
| 134 | poly_points: [], | ||
| 135 | point_insert_idx: 0, | 134 | point_insert_idx: 0, |
| 136 | }; | 135 | }; |
| 137 | } | 136 | } |
| @@ -140,8 +139,7 @@ function lib_shape_create_from_descriptor(desc) { | |||
| 140 | return { | 139 | return { |
| 141 | kind: desc.kind, | 140 | kind: desc.kind, |
| 142 | points: desc.points, | 141 | points: desc.points, |
| 143 | poly: null, | 142 | layers: [], |
| 144 | poly_points: [], | ||
| 145 | point_insert_idx: desc.points.length, | 143 | point_insert_idx: desc.points.length, |
| 146 | }; | 144 | }; |
| 147 | } | 145 | } |
| @@ -160,6 +158,12 @@ function page_shape__on_shape_delete(state) { | |||
| 160 | state.selected_shape = null; | 158 | state.selected_shape = null; |
| 161 | } | 159 | } |
| 162 | 160 | ||
| 161 | function page_shape__on_shape_delete_vertex(state) { | ||
| 162 | if (state.delete_selected_vertex_fn == null) | ||
| 163 | return; | ||
| 164 | state.delete_selected_vertex_fn(); | ||
| 165 | } | ||
| 166 | |||
| 163 | function page_shape__on_shape_kind_unburned(state) { | 167 | function page_shape__on_shape_kind_unburned(state) { |
| 164 | if (state.selected_shape == null) | 168 | if (state.selected_shape == null) |
| 165 | return; | 169 | return; |
| @@ -221,6 +225,7 @@ function page_shape__on_map_click(state, ev) { | |||
| 221 | function page_shape__setup_handlers(state) { | 225 | function page_shape__setup_handlers(state) { |
| 222 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_CREATE, () => page_shape__on_shape_create(state)); | 226 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_CREATE, () => page_shape__on_shape_create(state)); |
| 223 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_DELETE, () => page_shape__on_shape_delete(state)); | 227 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_DELETE, () => page_shape__on_shape_delete(state)); |
| 228 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_DELETE_VERTEX, () => page_shape__on_shape_delete_vertex(state)); | ||
| 224 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_UNBURNED, () => page_shape__on_shape_kind_unburned(state)); | 229 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_UNBURNED, () => page_shape__on_shape_kind_unburned(state)); |
| 225 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_BURNED, () => page_shape__on_shape_kind_burned(state)); | 230 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPE_BURNED, () => page_shape__on_shape_kind_burned(state)); |
| 226 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPES_UPDATE, () => page_shape__on_shapes_update(state)); | 231 | lib_setup_handler_onclick(ELEM_ID_BTN_SHAPES_UPDATE, () => page_shape__on_shapes_update(state)); |
| @@ -229,16 +234,11 @@ function page_shape__setup_handlers(state) { | |||
| 229 | } | 234 | } |
| 230 | 235 | ||
| 231 | function page_shape__ui_shape_remove(state, shape) { | 236 | function page_shape__ui_shape_remove(state, shape) { |
| 232 | for (const circle of shape.poly_points) { | 237 | for (const layer of shape.layers) { |
| 233 | state.map.removeLayer(circle); | 238 | state.map.removeLayer(layer); |
| 234 | } | 239 | layer.remove(); |
| 235 | shape.poly_points = []; | ||
| 236 | |||
| 237 | if (shape.poly != null) { | ||
| 238 | state.map.removeLayer(shape.poly); | ||
| 239 | shape.poly.remove(); | ||
| 240 | shape.poly = null; | ||
| 241 | } | 240 | } |
| 241 | shape.layers = []; | ||
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | function page_shape__ui_shape_select(state, shape) { | 244 | function page_shape__ui_shape_select(state, shape) { |
| @@ -252,41 +252,59 @@ function page_shape__ui_shape_select(state, shape) { | |||
| 252 | function page_shape__ui_shape_add(state, shape) { | 252 | function page_shape__ui_shape_add(state, shape) { |
| 253 | page_shape__ui_shape_remove(state, shape); | 253 | page_shape__ui_shape_remove(state, shape); |
| 254 | 254 | ||
| 255 | const selected = state.selected_shape == shape; | ||
| 255 | const color = lib_shape_color_for_kind(shape.kind); | 256 | const color = lib_shape_color_for_kind(shape.kind); |
| 256 | const positions = []; | 257 | const positions = []; |
| 257 | for (var i = 0; i < shape.points.length; i += 1) { | 258 | for (var i = 0; i < shape.points.length; i += 1) { |
| 258 | const point = shape.points[i]; | 259 | const point = shape.points[i]; |
| 259 | const highlight_point = shape.point_insert_idx - 1 == i; | 260 | const highlight_point = (shape.point_insert_idx - 1 == i) && selected; |
| 260 | const coords = [point.latitude, point.longitude]; | 261 | const coords = [point.latitude, point.longitude]; |
| 261 | const circle_color = highlight_point ? 'blue' : 'red'; | 262 | const circle_color = highlight_point ? 'blue' : 'red'; |
| 262 | const circle_idx = i; | 263 | const circle_idx = i; |
| 263 | console.assert(point.latitude != null, "invalid point latitude") | 264 | console.assert(point.latitude != null, "invalid point latitude") |
| 264 | console.assert(point.longitude != null, "invalid point longitude") | 265 | console.assert(point.longitude != null, "invalid point longitude") |
| 265 | 266 | ||
| 267 | const remove_circle = () => { | ||
| 268 | shape.points.splice(circle_idx, 1); | ||
| 269 | shape.point_insert_idx = circle_idx; | ||
| 270 | page_shape__ui_shape_add(state, shape); | ||
| 271 | }; | ||
| 272 | const update_insert_idx = () => { | ||
| 273 | shape.point_insert_idx = circle_idx + 1; | ||
| 274 | page_shape__ui_shape_add(state, shape); | ||
| 275 | }; | ||
| 276 | |||
| 277 | if (highlight_point) | ||
| 278 | state.delete_selected_vertex_fn = remove_circle; | ||
| 279 | |||
| 266 | positions.push(coords); | 280 | positions.push(coords); |
| 267 | const circle = L.circle(coords, { radius: 15, color: circle_color, bubblingMouseEvents: false }) | 281 | const circle = L.circle(coords, { radius: 15, color: circle_color, bubblingMouseEvents: false }) |
| 268 | .on('click', (e) => { | 282 | .on('click', (e) => { |
| 269 | if (e.originalEvent.shiftKey) { | 283 | if (e.originalEvent.shiftKey) { |
| 270 | shape.points.splice(circle_idx, 1); | 284 | remove_circle(); |
| 271 | shape.point_insert_idx = circle_idx; | ||
| 272 | page_shape__ui_shape_add(state, shape); | ||
| 273 | } else { | 285 | } else { |
| 274 | console.log(`clicked on circle, setting point insert idx to ${circle_idx + 1}`); | 286 | update_insert_idx(); |
| 275 | shape.point_insert_idx = circle_idx + 1; | ||
| 276 | page_shape__ui_shape_add(state, shape); | ||
| 277 | } | 287 | } |
| 278 | }) | 288 | }) |
| 289 | .on('contextmenu', () => remove_circle()) | ||
| 279 | .addTo(state.map); | 290 | .addTo(state.map); |
| 280 | shape.poly_points.push(circle); | 291 | shape.layers.push(circle); |
| 292 | |||
| 293 | if (selected) { | ||
| 294 | const tooltip = L.tooltip(coords, { content: `${i}` }) | ||
| 295 | .addTo(state.map); | ||
| 296 | shape.layers.push(tooltip); | ||
| 297 | } | ||
| 281 | } | 298 | } |
| 282 | 299 | ||
| 283 | if (positions.length >= 3) { | 300 | if (positions.length >= 3) { |
| 284 | const opacity = state.selected_shape == shape ? 0.2 : 0.04; | 301 | const opacity = state.selected_shape == shape ? 0.2 : 0.04; |
| 285 | shape.poly = L.polygon(positions, { color: color, fillOpacity: opacity, bubblingMouseEvents: false }) | 302 | const poly = L.polygon(positions, { color: color, fillOpacity: opacity, bubblingMouseEvents: false }) |
| 286 | .on('click', () => { | 303 | .on('click', () => { |
| 287 | page_shape__ui_shape_select(state, shape); | 304 | page_shape__ui_shape_select(state, shape); |
| 288 | }) | 305 | }) |
| 289 | .addTo(state.map); | 306 | .addTo(state.map); |
| 307 | shape.layers.push(poly); | ||
| 290 | } | 308 | } |
| 291 | } | 309 | } |
| 292 | 310 | ||
| @@ -300,6 +318,7 @@ async function page_shape__main() { | |||
| 300 | locations: locations, | 318 | locations: locations, |
| 301 | shapes: [], | 319 | shapes: [], |
| 302 | selected_shape: null, | 320 | selected_shape: null, |
| 321 | delete_selected_vertex_fn: null, | ||
| 303 | }; | 322 | }; |
| 304 | window.state = state; // to allow access from the console | 323 | window.state = state; // to allow access from the console |
| 305 | 324 | ||
