diff --git a/src/map.html b/src/map.html index 878ab9b..faaf7f0 100644 --- a/src/map.html +++ b/src/map.html @@ -15,11 +15,39 @@ right: 0.5em; background-color: rgba(70, 115, 164, 0.7); color: #eee; + white-space: nowrap; + max-height: calc(100vh - 1em); + overflow-y: auto; + } + .layer-toggles > div { + margin: 0.5em; + margin-right: 1em; } .ol-control.layer-toggles:hover { background-color: rgba(0,60,136,0.7); } - .layer-toggles > label { + .layer-toggles > div > label { + display: block; + } + .expand { + display: none; + } + .expand + span::before { + content: '\25B6'; + } + .expand:checked + span::before { + content: '\25BC'; + } + .expand ~ .collapsible-content { + display: none; + } + .expand:checked ~ .collapsible-content { + display: block; + } + .collapsible-content { + margin-left: 0.8em; + } + .collapsible-content label { display: block; } diff --git a/src/map.js b/src/map.js index 6c90253..2ccddd7 100644 --- a/src/map.js +++ b/src/map.js @@ -1,12 +1,11 @@ import 'ol/ol.css'; import {Map as olMap, View} from 'ol'; import {Control} from 'ol/control'; -import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer'; +import {Group as LayerGroup, Tile as TileLayer, Vector as VectorLayer} from 'ol/layer'; import {OSM, Vector as VectorSource} from 'ol/source'; import Feature from 'ol/Feature'; import {fromLonLat} from 'ol/proj'; -import {Icon, Fill, Stroke, Style, Text} from 'ol/style'; -import CircleStyle from 'ol/style/Circle'; +import {Circle as CircleStyle, Icon, Fill, Stroke, Style, Text} from 'ol/style'; import Projection from 'ol/proj/Projection'; import {LineString, Point} from 'ol/geom'; @@ -175,11 +174,9 @@ function plotPacketPaths(packets) { tile_layer.getSource().getProjection()); }); - let packet_path_layer = new VectorLayer({ - title: "Packet Paths", - source: new VectorSource(), - }); - map.addLayer(packet_path_layer); + let packet_path_layers = new LayerGroup({title: "Packet Paths"}); + let layers_map = new Map(); + map.addLayer(packet_path_layers); packets .filter(packet => packet.date > new Date("2018-07-14") && packet.date < new Date("2018-07-15")) // filter by callsign @@ -192,13 +189,11 @@ function plotPacketPaths(packets) { if (digiPos.get(station) === undefined) { console.log(station); } - let previous; - if (index === 0) { - previous = [packet.data.longitude, packet.data.latitude]; - } - else { - previous = digiPos.get(stations[index - 1]) || [0, 0]; - } + + // first point in path is originating station + let previous = (index === 0) ? + [packet.data.longitude, packet.data.latitude] : + digiPos.get(stations[index - 1]) || [0, 0]; let pathFeature = new Feature( new LineString([previous, digiPos.get(station) || [0, 0]])); @@ -211,7 +206,17 @@ function plotPacketPaths(packets) { {color: 'hsl(' + color + ', 60%, 60%)', width: 2} )})); - packet_path_layer.getSource().addFeature(pathFeature); + if (!layers_map.has(station)) { + layers_map.set(station, new VectorLayer({ + title: station, + source: new VectorSource(), + renderMode: 'image', + features: [pathFeature] + })); + packet_path_layers.getLayers().push(layers_map.get(station)); + } + layers_map.get(station).getSource().addFeature(pathFeature); + pathFeature.getGeometry().transform(new Projection({code: "EPSG:4326"}), tile_layer.getSource().getProjection()); }); @@ -220,26 +225,52 @@ function plotPacketPaths(packets) { let element = document.createElement('div'); element.className = 'layer-toggles ol-unselectable ol-control'; +let inner = element.appendChild(document.createElement('div')); + +function layer_toggle(layer, parentElement) { + if (layer.toggle_element === undefined) { + layer.toggle_element = parentElement.appendChild( + document.createElement('label')); + + let checkbox = layer.toggle_element.appendChild( + document.createElement('input')); + checkbox.type = "checkbox"; + checkbox.checked = layer.getVisible(); + checkbox.addEventListener('change', event => { + layer.setVisible(event.target.checked); + }); + layer.toggle_element.appendChild( + document.createTextNode(layer.get('title'))); + } + return layer.toggle_element; +} + function render_layer_toggles(event) { event.map.getLayers().getArray() .filter(layer => layer.get('title') !== undefined) .forEach(layer => { - if (layer.toggle_element === undefined) { - layer.toggle_element = element.appendChild( - document.createElement('label')); - - let checkbox = layer.toggle_element.appendChild( - document.createElement('input')); - checkbox.type = "checkbox"; - checkbox.checked = layer.getVisible(); - checkbox.addEventListener('change', event => { - layer.setVisible(event.target.checked); - }); - layer.toggle_element.appendChild( - document.createTextNode(layer.get('title'))); + console.log(layer.get('title')); + if (layer instanceof LayerGroup) { + if (layer.group_toggle === undefined) { + let label = layer.group_toggle = inner.appendChild( + document.createElement('label')); + let input = label.appendChild(document.createElement('input')); + input.type = 'checkbox'; + input.className = "expand"; + label.appendChild(document.createElement('span')); + layer_toggle(layer, label); // whole LayerGroup + let container = label.appendChild(document.createElement('div')); + container.className = 'collapsible-content'; + layer.getLayers().forEach( + sublayer => layer_toggle(sublayer, container)); + } } + else { + layer_toggle(layer, inner); + } }); } + let control = new Control({element: element, render: render_layer_toggles});