From 6abe668740a189ebb6de65693bebe0b76c6995b2 Mon Sep 17 00:00:00 2001 From: vjrj Date: Sun, 18 Nov 2018 11:48:03 +0100 Subject: [PATCH] Added fires union (wip) --- imports/api/ActiveFires/ActiveFires.js | 6 +- .../ActiveFiresUnion/server/publications.js | 78 +++++++++++++++++++ imports/startup/server/api.js | 1 + imports/ui/components/Maps/FireCircleMark.js | 12 ++- imports/ui/components/Maps/FireIconMark.js | 15 +--- imports/ui/components/Maps/FireListUnion.js | 22 ++++++ imports/ui/components/Maps/FirePixel.js | 19 ++--- imports/ui/components/Maps/FirePolygonMark.js | 48 ++++++++++++ imports/ui/pages/Fires/Fires.js | 20 ++--- imports/ui/pages/FiresMap/FiresMap.js | 27 ++++++- package-lock.json | 6 +- package.json | 2 +- 12 files changed, 216 insertions(+), 40 deletions(-) create mode 100644 imports/api/ActiveFiresUnion/server/publications.js create mode 100644 imports/ui/components/Maps/FireListUnion.js create mode 100644 imports/ui/components/Maps/FirePolygonMark.js diff --git a/imports/api/ActiveFires/ActiveFires.js b/imports/api/ActiveFires/ActiveFires.js index 79437af..16e2760 100644 --- a/imports/api/ActiveFires/ActiveFires.js +++ b/imports/api/ActiveFires/ActiveFires.js @@ -1,5 +1,6 @@ /* eslint-disable consistent-return */ +import { Meteor } from 'meteor/meteor'; import { Mongo } from 'meteor/mongo'; import SimpleSchema from 'simpl-schema'; import firesCommonSchema from '../Common/FiresSchema'; @@ -18,8 +19,11 @@ ActiveFires.deny({ remove: () => true }); +const activeFiresSchema = firesCommonSchema; -ActiveFires.schema = new SimpleSchema(firesCommonSchema); +activeFiresSchema.fireUnion = { type: Meteor.Collection.ObjectID, optional: true, blackbox: true }; + +ActiveFires.schema = new SimpleSchema(activeFiresSchema); ActiveFires.attachSchema(ActiveFires.schema); diff --git a/imports/api/ActiveFiresUnion/server/publications.js b/imports/api/ActiveFiresUnion/server/publications.js new file mode 100644 index 0000000..9ea010c --- /dev/null +++ b/imports/api/ActiveFiresUnion/server/publications.js @@ -0,0 +1,78 @@ +/* global Counter */ +/* eslint-disable import/no-absolute-path */ +/* eslint-disable prefer-arrow-callback */ + +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import { NumberBetween } from '/imports/modules/server/other-checks'; +// import { whichAreFalsePositives, firesUnion } from '/imports/api/FalsePositives/server/publications'; +// import FalsePositives from '/imports/api/FalsePositives/FalsePositives'; +// import Industries from '/imports/api/Industries/Industries'; +import ActiveFiresUnion from '../ActiveFiresUnion'; + +const counter = new Counter('countActiveFiresUnion', ActiveFiresUnion.find({})); + +Meteor.publish('activefiresuniontotal', function total() { + return counter; +}); + +const activeFiresUnion = (b1, b2, c1, c2, withMarks) => { + // a --- b + // c --- d + const geometry = { + $geometry: { + type: 'Polygon', + coordinates: [[ + [c1, c2], + [c1, b2], + [b1, b2], + [b1, c2], + [c1, c2] + ]] + } + }; + // console.log(JSON.stringify(geometry)); + const fires = ActiveFiresUnion.find({ + shape: { + $geoIntersects: geometry + } + }, { + fields: { + shape: 1, + centerid: 1, + when: 1, + createdAt: 1, + updatedAt: 1 + } + }); + + if (Meteor.isDevelopment) console.log(`Active fires union total: ${fires.count()}`); + + /* + if (withMarks && fires.fetch().length > 0) { + const union = firesUnion(fires); + const falsePos = whichAreFalsePositives(FalsePositives, union); + const industries = whichAreFalsePositives(Industries, union); + return [fires, falsePos, industries]; + } */ + + return fires; +}; + +Meteor.publish('activefiresunionmyloc', function activeInMyLoc(northEastLng, northEastLat, southWestLng, southWestLat, withMarks) { + // 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)); + check(withMarks, Boolean); + + if (!Meteor.isDevelopment) return this.ready(); // empty + return activeFiresUnion(northEastLng, northEastLat, southWestLng, southWestLat, withMarks); +}); + +// Warning: this increase always by one the fire stats +Meteor.publish('lastFireUnionDetected', function lastFireDetected() { + if (!Meteor.isDevelopment) return this.ready(); // empty + return ActiveFiresUnion.find({}, { limit: 1, sort: { when: -1 } }); +}); diff --git a/imports/startup/server/api.js b/imports/startup/server/api.js index 73f1fa2..a6044b4 100644 --- a/imports/startup/server/api.js +++ b/imports/startup/server/api.js @@ -9,6 +9,7 @@ import '../../api/Users/server/publications'; import '../../api/Utility/server/methods'; import '../../api/ActiveFires/server/publications'; +import '../../api/ActiveFiresUnion/server/publications'; import '../../api/FireAlerts/server/publications'; import '../../api/Subscriptions/methods'; diff --git a/imports/ui/components/Maps/FireCircleMark.js b/imports/ui/components/Maps/FireCircleMark.js index e4a3460..901d905 100644 --- a/imports/ui/components/Maps/FireCircleMark.js +++ b/imports/ui/components/Maps/FireCircleMark.js @@ -1,10 +1,10 @@ import React, { Component } from 'react'; -import { Circle } from 'react-leaflet'; +import { GeoJSON } from 'react-leaflet'; import PropTypes from 'prop-types'; +import { rectangleAround } from 'map-common-utils'; import { onMarkClick } from './MarkListeners'; import FirePopup from './FirePopup'; - class FireCircleMark extends Component { constructor(props) { super(props); @@ -22,22 +22,26 @@ class FireCircleMark extends Component { lat, lon, scan, + track, nasa, id, history, when, t } = this.props; + const rect = rectangleAround({ lat, lon }, track, track); return ( - + - + ); + /* */ } } FireCircleMark.propTypes = { scan: PropTypes.number.isRequired, + track: PropTypes.number.isRequired, lat: PropTypes.number.isRequired, lon: PropTypes.number.isRequired, nasa: PropTypes.bool.isRequired, diff --git a/imports/ui/components/Maps/FireIconMark.js b/imports/ui/components/Maps/FireIconMark.js index 94d93a0..ab24da4 100644 --- a/imports/ui/components/Maps/FireIconMark.js +++ b/imports/ui/components/Maps/FireIconMark.js @@ -3,8 +3,8 @@ import React, { Component, Fragment } from 'react'; import { CircleMarker, Marker, Tooltip } from 'react-leaflet'; import PropTypes from 'prop-types'; import { fireIconS, fireIconM, fireIconL, nFireIcon, industryIcon, regIndustryIcon } from '/imports/ui/components/Maps/Icons'; -import { onMarkClick } from './MarkListeners'; import { translate } from 'react-i18next'; +import { onMarkClick } from './MarkListeners'; import FirePopup from './FirePopup'; class FireIconMark extends Component { @@ -30,17 +30,7 @@ class FireIconMark extends Component { render() { const { - lat, - lon, - scan, - nasa, - id, - history, - falsePositives, - industries, - neighbour, - when, - t + lat, lon, scan, track, nasa, id, history, falsePositives, industries, neighbour, when, t } = this.props; return (
@@ -79,6 +69,7 @@ FireIconMark.propTypes = { lat: PropTypes.number.isRequired, lon: PropTypes.number.isRequired, scan: PropTypes.number, + track: PropTypes.number, nasa: PropTypes.bool, falsePositives: PropTypes.bool.isRequired, industries: PropTypes.bool.isRequired, diff --git a/imports/ui/components/Maps/FireListUnion.js b/imports/ui/components/Maps/FireListUnion.js new file mode 100644 index 0000000..3b094c0 --- /dev/null +++ b/imports/ui/components/Maps/FireListUnion.js @@ -0,0 +1,22 @@ +/* eslint-disable import/no-absolute-path */ +/* eslint-disable react/jsx-indent-props */ +/* eslint-disable react/jsx-indent */ +import React from 'react'; +import PropTypes from 'prop-types'; +import FirePolygonMark from '/imports/ui/components/Maps/FirePolygonMark'; + +export default function FireListUnion(props) { + const { + firesUnion, nasa, t, history + } = props; + /* console.log(`Using marks: ${useMarks}, using pixels: ${usePixel}`); */ + const items = firesUnion.map(({ _id, ...otherProps }) => ()); + return (
{items}
); +} + +FireListUnion.propTypes = { + firesUnion: PropTypes.array.isRequired, + nasa: PropTypes.bool.isRequired, + history: PropTypes.object.isRequired, + t: PropTypes.func.isRequired +}; diff --git a/imports/ui/components/Maps/FirePixel.js b/imports/ui/components/Maps/FirePixel.js index c81b547..4efcabe 100644 --- a/imports/ui/components/Maps/FirePixel.js +++ b/imports/ui/components/Maps/FirePixel.js @@ -3,31 +3,32 @@ import React from 'react'; import { CircleMarker } from 'react-leaflet'; import PropTypes from 'prop-types'; -import FirePopup from './FirePopup'; import { translate } from 'react-i18next'; +import FirePopup from './FirePopup'; /* Less acurate (1 pixel per fire) but faster */ const FirePixel = ({ - lat, lon, nasa, id, when, t, history + lat, lon, nasa, id, when, t, history, track }) => ( ); - FirePixel.propTypes = { lat: PropTypes.number.isRequired, lon: PropTypes.number.isRequired, id: PropTypes.object.isRequired, history: PropTypes.object.isRequired, + scan: PropTypes.number, + track: PropTypes.number, when: PropTypes.instanceOf(Date), nasa: PropTypes.bool.isRequired, t: PropTypes.func.isRequired diff --git a/imports/ui/components/Maps/FirePolygonMark.js b/imports/ui/components/Maps/FirePolygonMark.js new file mode 100644 index 0000000..92e3640 --- /dev/null +++ b/imports/ui/components/Maps/FirePolygonMark.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react'; +import { GeoJSON } from 'react-leaflet'; +import PropTypes from 'prop-types'; +import { onMarkClick } from './MarkListeners'; +import FirePopup from './FirePopup'; + +class FirePolygonMark extends Component { + constructor(props) { + super(props); + this.t = props.t; + this.onClick = this.onClick.bind(this); + } + + onClick() { + const { history, nasa, id } = this.props; + onMarkClick(history, nasa, id); + } + + render() { + const { + nasa, + id, + shape, + centerid, + history, + when, + t + } = this.props; + const lon = centerid.coordinates[0]; + const lat = centerid.coordinates[1]; + return ( + + ); + /* */ + } +} + +FirePolygonMark.propTypes = { + id: PropTypes.object.isRequired, + nasa: PropTypes.bool.isRequired, + shape: PropTypes.object.isRequired, + centerid: PropTypes.object.isRequired, + history: PropTypes.object.isRequired, + when: PropTypes.instanceOf(Date).isRequired, + t: PropTypes.func.isRequired +}; + +export default FirePolygonMark; diff --git a/imports/ui/pages/Fires/Fires.js b/imports/ui/pages/Fires/Fires.js index 0e4271a..ed7ef58 100644 --- a/imports/ui/pages/Fires/Fires.js +++ b/imports/ui/pages/Fires/Fires.js @@ -10,7 +10,8 @@ import { Row, Col, Alert, FormGroup } from 'react-bootstrap'; import { Meteor } from 'meteor/meteor'; import { Bert } from 'meteor/themeteorchef:bert'; import { Helmet } from 'react-helmet'; -import { Map, Circle } from 'react-leaflet'; +import { Map, GeoJSON } from 'react-leaflet'; +import { rectangleAround } from 'map-common-utils'; import Blaze from 'meteor/gadicc:blaze-react-component'; import DefMapLayers from '/imports/ui/components/Maps/DefMapLayers'; import NotFound from '/imports/ui/pages/NotFound/NotFound'; @@ -115,8 +116,9 @@ class Fire extends React.Component { t('Información adicional sobre fuego detectado en {{where}} el {{when}}', { where: fire.address, when: this.dateLongFormat }) : t('Información adicional sobre fuego detectado el {{when}}', { when: this.dateLongFormat }); } - - return (fire && !loading ? ( + const ready = fire && !loading; + const rect = ready ? rectangleAround({ lat: fire.lat, lon: fire.lon }, fire.track, fire.track) : null; + return (ready ? (
{t('AppName')}: {t('Información adicional sobre fuego')} @@ -137,13 +139,13 @@ class Fire extends React.Component { zoom={13} > - { this.circle = circle; this.handleLeafletCircleLoad(circle); }} /> diff --git a/imports/ui/pages/FiresMap/FiresMap.js b/imports/ui/pages/FiresMap/FiresMap.js index a5573b5..09ceacd 100644 --- a/imports/ui/pages/FiresMap/FiresMap.js +++ b/imports/ui/pages/FiresMap/FiresMap.js @@ -23,9 +23,11 @@ import 'leaflet-sleep/Leaflet.Sleep.js'; import geolocation from '/imports/startup/client/geolocation'; import CenterInMyPosition from '/imports/ui/components/CenterInMyPosition/CenterInMyPosition'; import FireList from '/imports/ui/components/Maps/FireList'; +import FireListUnion from '/imports/ui/components/Maps/FireListUnion'; import subsUnion from '/imports/ui/components/Maps/SubsUnion/SubsUnion'; import DefMapLayers from '/imports/ui/components/Maps/DefMapLayers'; import ActiveFiresCollection from '/imports/api/ActiveFires/ActiveFires'; +import ActiveFiresUnion from '/imports/api/ActiveFiresUnion/ActiveFiresUnion'; import FireAlertsCollection from '/imports/api/FireAlerts/FireAlerts'; import IndustriesCollection, { industriesRemap } from '/imports/api/Industries/Industries'; import FalsePositivesCollection, { falsePositivesRemap } from '/imports/api/FalsePositives/FalsePositives'; @@ -202,6 +204,7 @@ class FiresMap extends React.Component { if (Meteor.isDevelopment && this.props.activefires.length === 1) console.log(`Active fire: ${JSON.stringify(this.props.activefires[0])}`); if (Meteor.isDevelopment) console.log(`Active fires total: ${this.props.activefires.length}`); + if (Meteor.isDevelopment) console.log(`Active fires union total: ${this.props.activefiresunion.length}`); if (Meteor.isDevelopment) console.log(`False positives total: ${this.props.falsePositives.length}`); if (Meteor.isDevelopment) console.log(`Fire alerts total: ${this.props.firealerts.length}`); if (Meteor.isDevelopment) console.log(`Industries total: ${this.props.industries.length}`); @@ -307,6 +310,14 @@ class FiresMap extends React.Component { neighbour={false} industries={false} /> + { Meteor.isDevelopment && + + } { // console.log(`With industries: ${withIndustries}`); let subscription; + let subscriptionUnion; let alertSubscription; const centerStored = store.get('firesmap_center'); @@ -422,6 +436,14 @@ export default translate([], { wait: true })(withTracker(() => { mapSize.get()[1].lat, marks.get() && zoom.get() >= MAXZOOM ); + subscriptionUnion = Meteor.subscribe( + 'activefiresunionmyloc', + mapSize.get()[0].lng, + mapSize.get()[0].lat, + mapSize.get()[1].lng, + mapSize.get()[1].lat, + false + ); alertSubscription = Meteor.subscribe( 'fireAlerts', mapSize.get()[0].lng, @@ -442,6 +464,7 @@ export default translate([], { wait: true })(withTracker(() => { }); Meteor.subscribe('activefirestotal'); + Meteor.subscribe('activefiresuniontotal'); const settingsSubs = Meteor.subscribe('settings'); const lastCheck = SiteSettings.findOne({ name: 'last-fire-check' }); @@ -453,13 +476,15 @@ export default translate([], { wait: true })(withTracker(() => { const lastFireDetected = ActiveFiresCollection.findOne({}, { sort: { when: -1 } }); return { - loading: Meteor.status().status !== 'connected' || !subscription ? true : !(subscription.ready() && settingsSubs.ready() && alertSubscription.ready() && settingsSubs.ready()), + loading: Meteor.status().status !== 'connected' || !subscription ? true : !(subscription.ready() && settingsSubs.ready() && alertSubscription.ready() && settingsSubs.ready() && subscriptionUnion.ready()), userSubs: userSubs ? userSubs.value : null, userSubsBounds: userSubs ? userSubsBounds.value : null, subsready: settingsSubs.ready(), // Not reactive query depending on zoom level activefires: ActiveFiresCollection.find({}, { reactive: zoom.get() >= MAXZOOMREACTIVE }).fetch(), + activefiresunion: ActiveFiresUnion.find({}, { reactive: zoom.get() >= MAXZOOMREACTIVE }).fetch(), activefirestotal: Counter.get('countActiveFires') + fireAlerts.length, + activefiresuniontotal: Counter.get('countActiveFiresUnion') + fireAlerts.length, firealerts: fireAlerts, falsePositives, industries, diff --git a/package-lock.json b/package-lock.json index cdefe5b..77f558f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10835,9 +10835,9 @@ } }, "map-common-utils": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/map-common-utils/-/map-common-utils-0.4.0.tgz", - "integrity": "sha512-GjLGyIfusloAGwtaP7H15yzwmrMoHYVvx3+L5xiDBpjbRsgMphaaw+r+in0phwuQZApmGoA+VWV6ttQfTWqwWw==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/map-common-utils/-/map-common-utils-0.5.0.tgz", + "integrity": "sha512-dldbEOEMxlrzSWg+OgSJQgODW58D4ZYNCYVH8+kml+UY8XEB6Rpo3FO4YkMPqIqU5XlBIadPad9N2Br89NBBOQ==", "requires": { "@turf/bbox": "6.0.1", "@turf/bbox-polygon": "6.0.1", diff --git a/package.json b/package.json index b54e71b..76be651 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "leaflet-sleep": "^0.5.1", "lodash": "^4.17.4", "loms.perlin": "^1.0.1", - "map-common-utils": "^0.4.0", + "map-common-utils": "^0.5.0", "maxmind": "^2.3.0", "meteor-accounts-t9n": "^2.0.3", "meteor-node-stubs": "^0.3.2",