aboutsummaryrefslogtreecommitdiff
path: root/modern/src/MainMap.js
blob: 1a8542a626889e0a8fa7ff70d3fcc3dff727e6da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import 'mapbox-gl/src/css/mapbox-gl.css';
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: Array.from(state.positions.values()).map(position => ({
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [position.longitude, position.latitude]
      },
      properties: mapFeatureProperties(state, position)
    }))
  }
});

class MainMap extends Component {
  componentDidMount() {
    const map = new mapboxgl.Map({
      container: this.mapContainer,
      style: 'https://cdn.traccar.com/map/basic.json',
      center: [25.65, 60.98],
      zoom: 0
    });

    map.on('load', () => this.mapDidLoad(map));
  }

  loadImage(key, url) {
    const image = new Image();
    image.onload = () => {
      const canvas = document.createElement('canvas');
      canvas.width = image.width * window.devicePixelRatio;
      canvas.height = image.height * window.devicePixelRatio;
      canvas.style.width = `${image.width}px`;
      canvas.style.height = `${image.height}px`;
      const context = canvas.getContext('2d');
      context.drawImage(image, 0, 0, canvas.width, canvas.height);
      this.map.addImage(key, context.getImageData(0, 0, canvas.width, canvas.height), {
        pixelRatio: window.devicePixelRatio
      });
    }
    image.src = url;
  }

  mapDidLoad(map) {
    this.map = map;

    this.loadImage('background', 'images/background.svg');
    this.loadImage('icon-marker', 'images/icon/marker.svg');

    map.addSource('positions', {
      'type': 'geojson',
      'data': this.props.data
    });

    map.addLayer({
      'id': 'device-background',
      'type': 'symbol',
      'source': 'positions',
      'layout': {
        'icon-image': 'background',
        'icon-allow-overlap': true,
        'text-field': '{name}',
        'text-allow-overlap': true,
        'text-anchor': 'bottom',
        'text-offset': [0, -2],
        'text-font': ['Roboto Regular'],
        '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) {
    if (this.map && prevProps.data !== this.props.data) {
      this.map.getSource('positions').setData(this.props.data);
    }
  }

  render() {
    const style = {
      position: 'relative',
      overflow: 'hidden',
      width: '100%',
      height: '100%'
    };
    return <div style={style} ref={el => this.mapContainer = el} />;
  }
}

export default connect(mapStateToProps)(MainMap);