From 2c7dc9d42a44b5202b630a5db40e14147bf7c7f6 Mon Sep 17 00:00:00 2001 From: Victor Ferreira Date: Wed, 3 Oct 2018 09:42:25 -0300 Subject: Rename SocketContoller.js to SockerController.js fix filename --- modern/src/SocketController.js | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 modern/src/SocketController.js (limited to 'modern/src/SocketController.js') diff --git a/modern/src/SocketController.js b/modern/src/SocketController.js new file mode 100644 index 00000000..f65fc6c1 --- /dev/null +++ b/modern/src/SocketController.js @@ -0,0 +1,54 @@ +import { Component } from 'react'; +import { connect } from 'react-redux'; +import { updateDevices, updatePositions } from './actions'; + +const displayNotifications = events => { + if ("Notification" in window) { + if (Notification.permission === "granted") { + for (const event of events) { + const notification = new Notification(`Event: ${event.type}`); + setTimeout(notification.close.bind(notification), 4 * 1000); + } + } else if (Notification.permission !== "denied") { + Notification.requestPermission(permission => { + if (permission === "granted") { + displayNotifications(events); + } + }); + } + } +}; + +class SocketController extends Component { + connectSocket() { + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + const socket = new WebSocket(protocol + '//' + window.location.host + '/api/socket'); + + socket.onclose = () => { + setTimeout(() => this.connectSocket(), 60 * 1000); + }; + + socket.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data.devices) { + this.props.dispatch(updateDevices(data.devices)); + } + if (data.positions) { + this.props.dispatch(updatePositions(data.positions)); + } + if (data.events) { + displayNotifications(data.events); + } + } + } + + componentDidMount() { + this.connectSocket(); + } + + render() { + return null; + } +} + +export default connect()(SocketController); -- cgit v1.2.3 From 00daddce89f70989baecd8725e6df9bc88257b53 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 22 Mar 2020 17:32:36 -0700 Subject: Display features --- modern/public/images/background.svg | 2 +- modern/public/images/icon/marker.svg | 2 ++ modern/src/DeviceList.js | 13 +------------ modern/src/MainMap.js | 32 +++++++++++++++++++++++++------- modern/src/SocketController.js | 9 ++++++++- modern/src/reducers/index.js | 16 +++++++++++----- 6 files changed, 48 insertions(+), 26 deletions(-) create mode 100644 modern/public/images/icon/marker.svg (limited to 'modern/src/SocketController.js') diff --git a/modern/public/images/background.svg b/modern/public/images/background.svg index df2204d9..3dcb6870 100644 --- a/modern/public/images/background.svg +++ b/modern/public/images/background.svg @@ -1,4 +1,4 @@ - + diff --git a/modern/public/images/icon/marker.svg b/modern/public/images/icon/marker.svg new file mode 100644 index 00000000..f626547c --- /dev/null +++ b/modern/public/images/icon/marker.svg @@ -0,0 +1,2 @@ + + diff --git a/modern/src/DeviceList.js b/modern/src/DeviceList.js index c500242f..f636921d 100644 --- a/modern/src/DeviceList.js +++ b/modern/src/DeviceList.js @@ -1,6 +1,5 @@ import React, { Component, Fragment } from 'react'; import { connect } from 'react-redux'; -import { updateDevices } from './actions'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemAvatar from '@material-ui/core/ListItemAvatar'; @@ -13,20 +12,10 @@ import MoreVertIcon from '@material-ui/icons/MoreVert'; import Divider from '@material-ui/core/Divider'; const mapStateToProps = state => ({ - devices: state.devices + devices: Array.from(state.devices.values()) }); class DeviceList extends Component { - componentDidMount() { - fetch('/api/devices').then(response => { - if (response.ok) { - response.json().then(devices => { - this.props.dispatch(updateDevices(devices)); - }); - } - }); - } - render() { const devices = this.props.devices.map((device, index, list) => diff --git a/modern/src/MainMap.js b/modern/src/MainMap.js index 925b402a..1a8542a6 100644 --- a/modern/src/MainMap.js +++ b/modern/src/MainMap.js @@ -3,18 +3,22 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import mapboxgl from 'mapbox-gl'; +const mapFeatureProperties = (state, position) => { + return { + name: state.devices.get(position.deviceId).name + } +} + const mapStateToProps = state => ({ data: { type: 'FeatureCollection', - features: state.positions.map(position => ({ + features: Array.from(state.positions.values()).map(position => ({ type: 'Feature', geometry: { type: 'Point', coordinates: [position.longitude, position.latitude] }, - properties: { - ...position - } + properties: mapFeatureProperties(state, position) })) } }); @@ -40,7 +44,6 @@ class MainMap extends Component { canvas.style.width = `${image.width}px`; canvas.style.height = `${image.height}px`; const context = canvas.getContext('2d'); - context.imageSmoothingEnabled = false; context.drawImage(image, 0, 0, canvas.width, canvas.height); this.map.addImage(key, context.getImageData(0, 0, canvas.width, canvas.height), { pixelRatio: window.devicePixelRatio @@ -53,6 +56,7 @@ class MainMap extends Component { this.map = map; this.loadImage('background', 'images/background.svg'); + this.loadImage('icon-marker', 'images/icon/marker.svg'); map.addSource('positions', { 'type': 'geojson', @@ -65,15 +69,29 @@ class MainMap extends Component { 'source': 'positions', 'layout': { 'icon-image': 'background', - 'text-field': 'Test Device Name', + 'icon-allow-overlap': true, + 'text-field': '{name}', + 'text-allow-overlap': true, + 'text-anchor': 'bottom', + 'text-offset': [0, -2], 'text-font': ['Roboto Regular'], - 'text-size': 11 + 'text-size': 12 }, 'paint':{ 'text-halo-color': 'white', 'text-halo-width': 1 } }); + + map.addLayer({ + 'id': 'device-icon', + 'type': 'symbol', + 'source': 'positions', + 'layout': { + 'icon-image': 'icon-marker', + 'icon-allow-overlap': true + } + }); } componentDidUpdate(prevProps) { diff --git a/modern/src/SocketController.js b/modern/src/SocketController.js index f65fc6c1..b89845f2 100644 --- a/modern/src/SocketController.js +++ b/modern/src/SocketController.js @@ -43,7 +43,14 @@ class SocketController extends Component { } componentDidMount() { - this.connectSocket(); + fetch('/api/devices').then(response => { + if (response.ok) { + response.json().then(devices => { + this.props.dispatch(updateDevices(devices)); + }); + } + this.connectSocket(); + }); } render() { diff --git a/modern/src/reducers/index.js b/modern/src/reducers/index.js index ac592bfe..4593d1f3 100644 --- a/modern/src/reducers/index.js +++ b/modern/src/reducers/index.js @@ -1,20 +1,26 @@ const initialState = { - devices: [], - positions: [], - events: [] + devices: new Map(), + positions: new Map() }; +function updateMap(map, array, key) { + for (let value of array) { + map.set(value[key], value); + } + return map; +} + function rootReducer(state = initialState, action) { switch (action.type) { case 'UPDATE_DEVICES': return Object.assign({}, { ...state, - devices: [...action.devices] + devices: updateMap(state.devices, action.devices, 'id') }); case 'UPDATE_POSITIONS': return Object.assign({}, { ...state, - positions: [...action.positions] + positions: updateMap(state.positions, action.positions, 'deviceId') }); default: return state; -- cgit v1.2.3