Better publication and count of active fires in current map
This commit is contained in:
parent
96595b3aa4
commit
2fec833aef
4 changed files with 111 additions and 128 deletions
|
|
@ -3,8 +3,8 @@
|
|||
/* eslint-disable prefer-arrow-callback */
|
||||
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check, Match } from 'meteor/check';
|
||||
import { localize } from '/imports/startup/server/IPGeocoder';
|
||||
import { check } from 'meteor/check';
|
||||
import { NumberBetween } from '/imports/modules/server/other-checks';
|
||||
import ActiveFires from '../ActiveFires';
|
||||
|
||||
const counter = new Counter('countActiveFires', ActiveFires.find({}));
|
||||
|
|
@ -13,60 +13,14 @@ Meteor.publish('activefirestotal', function total() {
|
|||
return counter;
|
||||
});
|
||||
|
||||
const validZoom = Match.Where((zoom) => {
|
||||
// http://wiki.openstreetmap.org/wiki/Zoom_levels
|
||||
check(zoom, Number);
|
||||
return zoom >= 0 && zoom <= 19;
|
||||
});
|
||||
|
||||
// https://github.com/3stack-software/meteor-match-library
|
||||
function NumberBetween(min, max) {
|
||||
return Match.Where((x) => {
|
||||
check(x, Number);
|
||||
return min <= x && x <= max;
|
||||
});
|
||||
}
|
||||
|
||||
function NullOr(type) {
|
||||
return Match.Where((x) => {
|
||||
if (x === null) {
|
||||
return true;
|
||||
}
|
||||
check(x, type);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// http://wiki.openstreetmap.org/wiki/Zoom_levels
|
||||
// http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale
|
||||
|
||||
// http://cwestblog.com/2012/11/12/javascript-degree-and-radian-conversion/
|
||||
Math.radians = (degrees) => {
|
||||
const rad = (degrees * Math.PI) / 180;
|
||||
return rad;
|
||||
};
|
||||
|
||||
const activefires = (zoom, lat, lng, height, width) => {
|
||||
// latitude -90 and 90 and the longitude between -180 and 180
|
||||
check(lat, NumberBetween(-90, 90));
|
||||
check(lng, NumberBetween(-180, 180));
|
||||
|
||||
// console.log("Zoom: " + zoom + " lat: " + lat + " lng: " + lng);
|
||||
const resolution = (156543.03 * Math.cos(Math.radians(lat))) / (2 ** zoom);
|
||||
const distUnt = resolution * Math.max(height, width);
|
||||
const distance = Math.trunc(distUnt);
|
||||
// console.log(`so ${height}x${width} gives ${Math.trunc(resolution*height/1000)} x ${Math.trunc(resolution*width/1000)} km, so looking in ${distance}`);
|
||||
// console.log(`So ${height}x${width} gives ${Math.trunc(resolution)} of resolution, so looking in ${Math.trunc(distance / 1000)}km`);
|
||||
|
||||
const activefires = (northEastLng, northEastLat, southWestLng, southWestLat) => {
|
||||
const fires = ActiveFires.find({
|
||||
ourid: {
|
||||
$near: {
|
||||
$geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [lng, lat]
|
||||
},
|
||||
$minDistance: 0,
|
||||
$maxDistance: distance
|
||||
$geoWithin: {
|
||||
$box: [
|
||||
[southWestLng, southWestLat],
|
||||
[northEastLng, northEastLat]
|
||||
]
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
|
@ -80,48 +34,12 @@ const activefires = (zoom, lat, lng, height, width) => {
|
|||
return fires;
|
||||
};
|
||||
|
||||
|
||||
Meteor.publish('allActiveFires', function allActive() {
|
||||
Meteor.publish('activefiresmyloc', function activeInMyLoc(northEastLng, northEastLat, southWestLng, southWestLat) {
|
||||
// latitude -90 and 90 and the longitude between -180 and 180
|
||||
check(northEastLng, NumberBetween(-180, 180));
|
||||
check(southWestLat, NumberBetween(-90, 90));
|
||||
check(southWestLng, NumberBetween(-180, 180));
|
||||
check(northEastLat, NumberBetween(-90, 90));
|
||||
|
||||
const { latitude, longitude } = localize().location;
|
||||
// console.log(`${latitude}, ${longitude}`);
|
||||
check(latitude, NumberBetween(-90, 90));
|
||||
check(longitude, NumberBetween(-180, 180));
|
||||
// https://docs.meteor.com/api/collections.html#Mongo-Collection-find
|
||||
return ActiveFires.find({
|
||||
ourid: {
|
||||
$near: {
|
||||
$geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [longitude, latitude]
|
||||
},
|
||||
$minDistance: 0,
|
||||
$maxDistance: 1000 // 156412000
|
||||
}
|
||||
}
|
||||
}, {
|
||||
fields: {
|
||||
_id: 0,
|
||||
lat: 1,
|
||||
lon: 1,
|
||||
scan: 1
|
||||
},
|
||||
maxTimeMs: 30000
|
||||
});
|
||||
});
|
||||
|
||||
Meteor.publish('activefiresmyloc', function activeInMyLoc(zoom, lat, lng, height, width) {
|
||||
check(zoom, validZoom);
|
||||
check(lat, NullOr(Number));
|
||||
check(lng, NullOr(Number));
|
||||
check(height, NullOr(Number));
|
||||
check(width, NullOr(Number));
|
||||
// console.log(`Check active fires in ${lat},${lng} with zoom ${zoom} pixels in ${height}x${width} map`);
|
||||
if (lat && lng) {
|
||||
return activefires(zoom, lat, lng, height, width);
|
||||
}
|
||||
const geo = localize();
|
||||
// console.log(`${location.latitude}, ${location.longitude}`);
|
||||
return activefires(zoom, geo.location.latitude, geo.location.longitude, height, width);
|
||||
return activefires(northEastLng, northEastLat, southWestLng, southWestLat);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,42 @@
|
|||
/* eslint-disable prefer-arrow-callback */
|
||||
/* eslint-disable import/no-absolute-path */
|
||||
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import { NumberBetween } from '/imports/modules/server/other-checks';
|
||||
import moment from 'moment';
|
||||
import FireAlerts from '../FireAlerts';
|
||||
|
||||
Meteor.publish('fireAlerts', function fireAlerts() {
|
||||
return FireAlerts.find();
|
||||
Meteor.publish('fireAlerts', function fireAlerts(northEastLng, northEastLat, southWestLng, southWestLat) {
|
||||
// latitude -90 and 90 and the longitude between -180 and 180
|
||||
check(northEastLng, NumberBetween(-180, 180));
|
||||
check(southWestLat, NumberBetween(-90, 90));
|
||||
check(southWestLng, NumberBetween(-180, 180));
|
||||
check(northEastLat, NumberBetween(-90, 90));
|
||||
|
||||
// https://stackoverflow.com/questions/29327222/mongodb-find-created-results-by-date-today/29327353
|
||||
const start = new Date();
|
||||
start.setHours(0, 0, 0, 0);
|
||||
const end = new Date();
|
||||
end.setHours(23, 59, 59, 999);
|
||||
|
||||
const fires = FireAlerts.find({
|
||||
ourid: {
|
||||
$geoWithin: {
|
||||
$box: [
|
||||
[southWestLng, southWestLat],
|
||||
[northEastLng, northEastLat]
|
||||
]
|
||||
}
|
||||
},
|
||||
createdAt: { $gte: start, $lt: end }
|
||||
}, {
|
||||
fields: {
|
||||
lat: 1,
|
||||
lon: 1,
|
||||
scan: 1
|
||||
}
|
||||
});
|
||||
// console.log(`Fires total: ${fires.count()}`);
|
||||
return fires;
|
||||
});
|
||||
|
|
|
|||
25
imports/modules/server/other-checks.js
Normal file
25
imports/modules/server/other-checks.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { check, Match } from 'meteor/check';
|
||||
|
||||
export const validZoom = Match.Where((zoom) => {
|
||||
// http://wiki.openstreetmap.org/wiki/Zoom_levels
|
||||
check(zoom, Number);
|
||||
return zoom >= 0 && zoom <= 19;
|
||||
});
|
||||
|
||||
// https://github.com/3stack-software/meteor-match-library
|
||||
export function NumberBetween(min, max) {
|
||||
return Match.Where((x) => {
|
||||
check(x, Number);
|
||||
return min <= x && x <= max;
|
||||
});
|
||||
}
|
||||
|
||||
export function NullOr(type) {
|
||||
return Match.Where((x) => {
|
||||
if (x === null) {
|
||||
return true;
|
||||
}
|
||||
check(x, type);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
@ -34,8 +34,8 @@ import './FiresMap.scss';
|
|||
const MAXZOOM = 6;
|
||||
const MAXZOOMREACTIVE = 6;
|
||||
const zoom = new ReactiveVar(8);
|
||||
const center = new ReactiveVar([null, null]);
|
||||
const mapSize = new ReactiveVar([400, 400]);
|
||||
const center = new ReactiveVar([0, 0]);
|
||||
const mapSize = new ReactiveVar();
|
||||
|
||||
// Remove map in subscription
|
||||
class FiresMap extends React.Component {
|
||||
|
|
@ -59,9 +59,12 @@ class FiresMap extends React.Component {
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
mapSize.set([this.divElement.clientHeight, this.divElement.clientWidth]);
|
||||
if (this.fireMap) {
|
||||
this.addScale();
|
||||
if (this.getMap().getCenter()) {
|
||||
const bounds = this.getMap().getBounds();
|
||||
mapSize.set([bounds.getNorthEast(), bounds.getSouthWest()]);
|
||||
this.addScale();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,9 +72,6 @@ class FiresMap extends React.Component {
|
|||
this.debounceView(viewport);
|
||||
}
|
||||
|
||||
onClickReset() {
|
||||
}
|
||||
|
||||
getMap() {
|
||||
return this.fireMap.leafletElement;
|
||||
}
|
||||
|
|
@ -82,6 +82,10 @@ class FiresMap extends React.Component {
|
|||
|
||||
handleViewportChange(viewport) {
|
||||
console.log(`Viewport changed: ${JSON.stringify(viewport)}`);
|
||||
const bounds = this.getMap().getBounds();
|
||||
// console.log(bounds);
|
||||
mapSize.set([bounds.getNorthEast(), bounds.getSouthWest()]);
|
||||
/*
|
||||
if (viewport.center === this.state.viewport.center &&
|
||||
viewport.zoom === this.state.viewport.zoom) {
|
||||
// Do nothing, in same point
|
||||
|
|
@ -89,7 +93,7 @@ class FiresMap extends React.Component {
|
|||
}
|
||||
zoom.set(viewport.zoom);
|
||||
center.set(viewport.center);
|
||||
this.setState({ viewport });
|
||||
this.setState({ viewport }); */
|
||||
}
|
||||
|
||||
centerOnUserLocation(viewport) {
|
||||
|
|
@ -124,7 +128,7 @@ class FiresMap extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
console.log(`Rendering ${this.props.loading ? 'loading' : 'LOADED'} map ${this.props.activefires.length} of ${this.props.activefirestotal} total. Subs users ready ${this.props.subsready}, reactive ${this.state.viewport.zoom >= MAXZOOMREACTIVE}`);
|
||||
console.log(`Rendering ${this.props.loading ? 'loading' : 'LOADED'} map ${this.props.activefires.length + this.props.firealerts.length} of ${this.props.activefirestotal} total. Subs users ready ${this.props.subsready}, reactive ${this.state.viewport.zoom >= MAXZOOMREACTIVE}`);
|
||||
|
||||
return (
|
||||
/* Large number of markers:
|
||||
|
|
@ -141,9 +145,9 @@ class FiresMap extends React.Component {
|
|||
<Row>
|
||||
<Col xs={12} sm={6} md={6} lg={6} >
|
||||
<p className="firesmap-legend">
|
||||
{ this.props.activefires.length === 0 ?
|
||||
{ (this.props.activefires.length + this.props.firealerts.length) === 0 ?
|
||||
<Fragment><Trans parent="span" i18nKey="noActiveFireInMapCount">No hay fuegos activos en esta zona del mapa. Hay un total de <strong>{{ countTotal: this.props.activefirestotal }}</strong> fuegos activos detectados en todo el mundo.</Trans> <Trans>Datos actualizados <FromNow when={this.props.lastCheck} />.</Trans></Fragment> :
|
||||
<Fragment><Trans parent="span" i18nKey="activeFireInMapCount">En rojo, <strong>{{ count: this.props.activefires.length }}</strong> fuegos activos en el mapa. Hay un total de <strong>{{ countTotal: this.props.activefirestotal }}</strong> fuegos activos detectados en todo el mundo por la NASA.</Trans> <Trans>Datos actualizados <FromNow when={this.props.lastCheck} />.</Trans></Fragment>
|
||||
<Fragment><Trans parent="span" i18nKey="activeFireInMapCount">En rojo, <strong>{{ count: this.props.activefires.length + this.props.firealerts.length }}</strong> fuegos activos en el mapa. Hay un total de <strong>{{ countTotal: this.props.activefirestotal }}</strong> fuegos activos detectados en todo el mundo por la NASA.</Trans> <Trans>Datos actualizados <FromNow when={this.props.lastCheck} />.</Trans></Fragment>
|
||||
}
|
||||
</p>
|
||||
{isNotHomeAndMobile &&
|
||||
|
|
@ -178,6 +182,8 @@ class FiresMap extends React.Component {
|
|||
className="firesmap-leaflet-container"
|
||||
animate
|
||||
minZoom={5}
|
||||
center={this.props.center}
|
||||
zoom={this.props.zoom}
|
||||
preferCanvas
|
||||
onClick={this.onClickReset}
|
||||
viewport={this.state.viewport}
|
||||
|
|
@ -237,47 +243,47 @@ FiresMap.propTypes = {
|
|||
t: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
let init = true;
|
||||
|
||||
export default translate([], { wait: true })(withTracker(() => {
|
||||
let subscription;
|
||||
let init = true;
|
||||
Meteor.autorun(() => {
|
||||
if (geolocation.get() && init) {
|
||||
center.set(geolocation.get());
|
||||
// console.log(`Geolocation ${geolocation.get()}`);
|
||||
console.log(`Geolocation ${geolocation.get()}`);
|
||||
init = false;
|
||||
}
|
||||
if (mapSize.get()) {
|
||||
if (mapSize.get() && mapSize.get()[0].lng && mapSize.get()[1].lat) {
|
||||
subscription = Meteor.subscribe(
|
||||
'activefiresmyloc',
|
||||
zoom.get(),
|
||||
center.get()[0],
|
||||
center.get()[1],
|
||||
mapSize.get()[0],
|
||||
mapSize.get()[1]
|
||||
mapSize.get()[0].lng,
|
||||
mapSize.get()[0].lat,
|
||||
mapSize.get()[1].lng,
|
||||
mapSize.get()[1].lat
|
||||
);
|
||||
Meteor.subscribe(
|
||||
'fireAlerts',
|
||||
mapSize.get()[0].lng,
|
||||
mapSize.get()[0].lat,
|
||||
mapSize.get()[1].lng,
|
||||
mapSize.get()[1].lat
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Meteor.subscribe('activefirestotal');
|
||||
// Right now to all neighborhood alerts
|
||||
Meteor.subscribe('fireAlerts');
|
||||
Meteor.subscribe('settings');
|
||||
const userSubs = Meteor.subscribe('userSubsToFires');
|
||||
// const subscription = Meteor.subscribe('activefiresmyloc', zoom.get());
|
||||
// Warning with the performance of this log:
|
||||
// console.log(`Active fires ${ActiveFiresCollection.find().count()} of ${Counter.get('countActiveFires')}`);
|
||||
// console.log(`Active neighborhood fires ${FireAlertsCollection.find().fetch().length} and users subscribed ${UserSubsToFiresCollection.find().fetch().length}`);
|
||||
// console.log(UserSubsToFiresCollection.find().fetch());
|
||||
const lastCheck = SiteSettings.findOne({ name: 'last-fire-check' });
|
||||
const fireAlerts = FireAlertsCollection.find().fetch();
|
||||
return {
|
||||
loading: !subscription.ready(),
|
||||
loading: !subscription ? true : !subscription.ready(),
|
||||
userSubs: UserSubsToFiresCollection.find().fetch(),
|
||||
subsready: userSubs.ready(),
|
||||
// Not reactive query depending on zoom level
|
||||
activefires: ActiveFiresCollection.find({}, { reactive: zoom.get() >= MAXZOOMREACTIVE }).fetch(),
|
||||
// activefires: ActiveFiresCollection.find({}).fetch(),
|
||||
activefirestotal: Counter.get('countActiveFires'),
|
||||
firealerts: FireAlertsCollection.find().fetch(),
|
||||
activefirestotal: Counter.get('countActiveFires') + fireAlerts.length,
|
||||
firealerts: fireAlerts,
|
||||
lastCheck: lastCheck ? lastCheck.value : null,
|
||||
center: geolocation.get(),
|
||||
zoom: zoom.get()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue