mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 11:07:08 +00:00
Show events on map.
Partial implementation. Notably, it does not yet update when events are added/modified/deleted. Related to #48.
This commit is contained in:
@@ -16,12 +16,18 @@
|
||||
.theme--dark #map {
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
.cluster {
|
||||
border: 2px solid green;
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import L from 'leaflet'
|
||||
import 'leaflet-realtime'
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import 'leaflet.markercluster'
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import ftstamp from '@/lib/FormatTimestamp'
|
||||
import zoomFitIcon from '@/assets/zoom-fit-best.svg'
|
||||
|
||||
@@ -135,6 +141,10 @@ const layers = {
|
||||
layer.bindTooltip(popup, {sticky: true});
|
||||
}
|
||||
}),
|
||||
|
||||
"Events (QC)": L.geoJSON(null),
|
||||
|
||||
"Events (Other)": L.geoJSON(null),
|
||||
|
||||
"Real-time": L.realtime({
|
||||
url: '/api/navdata/gis/point?limit=1',
|
||||
@@ -235,6 +245,7 @@ function makeRealTimePopup(feature) {
|
||||
return popup;
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
name: "Map",
|
||||
|
||||
@@ -272,7 +283,8 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['loading', 'serverEvent', 'lineName'])
|
||||
...mapGetters(['loading', 'serverEvent', 'lineName', 'serverEvent']),
|
||||
...mapState({projectSchema: state => state.project.projectSchema})
|
||||
},
|
||||
|
||||
watch: {
|
||||
@@ -298,6 +310,8 @@ export default {
|
||||
};
|
||||
rtLayer.update(geojson);
|
||||
}
|
||||
} else if (event.channel == "event" && event.payload.schema == this.projectSchema) {
|
||||
console.log("EVENT", event);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -309,6 +323,44 @@ export default {
|
||||
const bbox = new L.GeoJSON(res);
|
||||
map.fitBounds(bbox.getBounds());
|
||||
},
|
||||
|
||||
getEvents (ffn = i => true) {
|
||||
return async (success, error) => {
|
||||
const url = `/project/${this.$route.params.project}/event`;
|
||||
const data = await this.api([url]);
|
||||
if (data) {
|
||||
|
||||
function colour(feature) {
|
||||
if (feature && feature.properties && feature.properties.type) {
|
||||
if (feature.properties.type == "qc") {
|
||||
return feature.properties.labels.includes("QCAccepted")
|
||||
? "lightgray"
|
||||
: "gray";
|
||||
} else if (feature.properties.type == "midnight shot") {
|
||||
return "cyan";
|
||||
} else {
|
||||
return "orange";
|
||||
}
|
||||
}
|
||||
return "brown";
|
||||
}
|
||||
|
||||
const features = data.filter(i => i.geometry).filter(ffn).map(i => {
|
||||
const feature = {
|
||||
type: "Feature",
|
||||
geometry: i.geometry,
|
||||
properties: i
|
||||
};
|
||||
feature.properties.colour = colour(feature);
|
||||
delete feature.properties.geometry;
|
||||
return feature;
|
||||
});
|
||||
success(features);
|
||||
} else {
|
||||
error("Failed to get events");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async refreshLayers (layerset) {
|
||||
|
||||
@@ -329,9 +381,17 @@ export default {
|
||||
// Firing all refresh events asynchronously, which is OK provided
|
||||
// we don't have hundreds of layers to be refreshed.
|
||||
await this.api([l.url(query)]).then( (layer) => {
|
||||
if (typeof l.transform == 'function') {
|
||||
layer = l.transform(layer);
|
||||
}
|
||||
|
||||
l.layer.clearLayers();
|
||||
if ((layer.features && layer.features.length < limit) || ("length" in layer && layer.length < limit)) {
|
||||
l.layer.addData(layer);
|
||||
if (layer instanceof L.Layer || (layer.features && layer.features.length < limit) || ("length" in layer && layer.length < limit)) {
|
||||
if (l.layer.addData) {
|
||||
l.layer.addData(layer);
|
||||
} else if (l.layer.addLayer) {
|
||||
l.layer.addLayer(layer);
|
||||
}
|
||||
} else {
|
||||
console.warn("Too much data from", l.url(query));
|
||||
}
|
||||
@@ -380,6 +440,35 @@ export default {
|
||||
|
||||
mounted () {
|
||||
map = L.map('map', {maxZoom: 22});
|
||||
|
||||
const eventsOptions = () => {
|
||||
return {
|
||||
//start: false,
|
||||
container: L.markerClusterGroup({maxClusterRadius: 1, className: "cluster"}),
|
||||
getFeatureId (feature) {
|
||||
return feature.properties.id;
|
||||
},
|
||||
pointToLayer (point, latlng) {
|
||||
return L.circleMarker(latlng, {
|
||||
radius: 5,
|
||||
color: point.properties.colour || "gray",
|
||||
stroke: false,
|
||||
fillOpacity: 0.6
|
||||
});
|
||||
},
|
||||
onEachFeature (feature, layer) {
|
||||
const p = feature.properties;
|
||||
const popup = (p.sequence
|
||||
? `Event @ ${p.tstamp}<br/>Sequence ${p.sequence}<br/>Point <b>${p.line} / ${p.point}</b><br/><hr/>${p.remarks}`
|
||||
: `Event @ ${p.tstamp}<br/><hr/>${p.remarks}`)
|
||||
+ (p.labels.length? `<br/>[<i>${p.labels.join(", ")}</i>]` : "");
|
||||
layer.bindTooltip(popup, {sticky: true});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
layers["Events (QC)"] = L.realtime(this.getEvents(i => i.type == "qc"), eventsOptions());
|
||||
layers["Events (Other)"] = L.realtime(this.getEvents(i => i.type != "qc"), eventsOptions());
|
||||
|
||||
const init = this.decodeURL();
|
||||
|
||||
@@ -436,7 +525,6 @@ export default {
|
||||
this.fitProjectBounds();
|
||||
}
|
||||
|
||||
|
||||
// /usr/share/icons/breeze/actions/16/zoom-fit-best.svg
|
||||
const fitProjectBounds = this.fitProjectBounds;
|
||||
const FitToBoundsControl = L.Control.extend({
|
||||
|
||||
Reference in New Issue
Block a user