aboutsummaryrefslogtreecommitdiff
path: root/modern/src/map/mapManager.js
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2020-10-24 11:52:27 -0700
committerAnton Tananaev <anton.tananaev@gmail.com>2020-10-24 11:52:27 -0700
commit5836e53995f4f70b1e33c108823cf6f3293078de (patch)
tree23093a615fa7e0655fc2356900825e1569139d2c /modern/src/map/mapManager.js
parent962267b2c5c2c33945880a360107c2812765c983 (diff)
downloadtrackermap-web-5836e53995f4f70b1e33c108823cf6f3293078de.tar.gz
trackermap-web-5836e53995f4f70b1e33c108823cf6f3293078de.tar.bz2
trackermap-web-5836e53995f4f70b1e33c108823cf6f3293078de.zip
Move map classes
Diffstat (limited to 'modern/src/map/mapManager.js')
-rw-r--r--modern/src/map/mapManager.js218
1 files changed, 218 insertions, 0 deletions
diff --git a/modern/src/map/mapManager.js b/modern/src/map/mapManager.js
new file mode 100644
index 00000000..9e5d631d
--- /dev/null
+++ b/modern/src/map/mapManager.js
@@ -0,0 +1,218 @@
+import 'mapbox-gl/dist/mapbox-gl.css';
+import mapboxgl from 'mapbox-gl';
+
+let ready = false;
+let registeredListener = null;
+
+const registerListener = listener => {
+ if (ready) {
+ listener();
+ } else {
+ registeredListener = listener;
+ }
+};
+
+const loadImage = (url) => {
+ return new Promise(imageLoaded => {
+ const image = new Image();
+ image.onload = () => imageLoaded(image);
+ image.src = url;
+ });
+};
+
+const loadIcon = (key, background, url) => {
+ return loadImage(url).then((image) => {
+ const canvas = document.createElement('canvas');
+ canvas.width = background.width * window.devicePixelRatio;
+ canvas.height = background.height * window.devicePixelRatio;
+ canvas.style.width = `${background.width}px`;
+ canvas.style.height = `${background.height}px`;
+ const context = canvas.getContext('2d');
+ context.drawImage(background, 0, 0, canvas.width, canvas.height);
+
+ const imageWidth = image.width * window.devicePixelRatio;
+ const imageHeight = image.height * window.devicePixelRatio;
+ context.drawImage(image, (canvas.width - imageWidth) / 2, (canvas.height - imageHeight) / 2, imageWidth, imageHeight);
+
+ map.addImage(key, context.getImageData(0, 0, canvas.width, canvas.height), {
+ pixelRatio: window.devicePixelRatio
+ });
+ });
+};
+
+const layerClickCallbacks = {};
+const layerMouseEnterCallbacks = {};
+const layerMauseLeaveCallbacks = {};
+
+const addLayer = (id, source, icon, text, onClick) => {
+ const layer = {
+ 'id': id,
+ 'type': 'symbol',
+ 'source': source,
+ 'layout': {
+ 'icon-image': icon,
+ 'icon-allow-overlap': true,
+ },
+ };
+ if (text) {
+ layer.layout = {
+ ...layer.layout,
+ 'text-field': text,
+ 'text-allow-overlap': true,
+ 'text-anchor': 'bottom',
+ 'text-offset': [0, -2],
+ 'text-font': ['Roboto Regular'],
+ 'text-size': 12,
+ }
+ layer.paint = {
+ 'text-halo-color': 'white',
+ 'text-halo-width': 1,
+ }
+ }
+ map.addLayer(layer);
+
+ layerClickCallbacks[id] = onClick;
+ map.on('click', id, onClick);
+
+ layerMouseEnterCallbacks[id] = () => {
+ map.getCanvas().style.cursor = 'pointer';
+ };
+ map.on('mouseenter', id, layerMouseEnterCallbacks[id]);
+
+ layerMauseLeaveCallbacks[id] = () => {
+ map.getCanvas().style.cursor = '';
+ };
+ map.on('mouseleave', id, layerMauseLeaveCallbacks[id]);
+}
+
+const removeLayer = (id, source) => {
+ const popups = element.getElementsByClassName('mapboxgl-popup');
+ if (popups.length) {
+ popups[0].remove();
+ }
+
+ map.off('click', id, layerClickCallbacks[id]);
+ delete layerClickCallbacks[id];
+
+ map.off('mouseenter', id, layerMouseEnterCallbacks[id]);
+ delete layerMouseEnterCallbacks[id];
+
+ map.off('mouseleave', id, layerMauseLeaveCallbacks[id]);
+ delete layerMauseLeaveCallbacks[id];
+
+ map.removeLayer(id);
+ map.removeSource(source);
+}
+
+const calculateBounds = features => {
+ if (features && features.length) {
+ const first = features[0].geometry.coordinates;
+ const bounds = [[...first], [...first]];
+ for (let feature of features) {
+ const longitude = feature.geometry.coordinates[0]
+ const latitude = feature.geometry.coordinates[1]
+ if (longitude < bounds[0][0]) {
+ bounds[0][0] = longitude;
+ } else if (longitude > bounds[1][0]) {
+ bounds[1][0] = longitude;
+ }
+ if (latitude < bounds[0][1]) {
+ bounds[0][1] = latitude;
+ } else if (latitude > bounds[1][1]) {
+ bounds[1][1] = latitude;
+ }
+ }
+ return bounds;
+ } else {
+ return null;
+ }
+}
+
+const element = document.createElement('div');
+element.style.width = '100%';
+element.style.height = '100%';
+
+/*const map = new mapboxgl.Map({
+ container: this.mapContainer,
+ style: 'https://cdn.traccar.com/map/basic.json',
+ center: [0, 0],
+ zoom: 1
+});*/
+
+/*const map = new mapboxgl.Map({
+ container: element,
+ style: {
+ 'version': 8,
+ 'sources': {
+ 'raster-tiles': {
+ 'type': 'raster',
+ 'tiles': [
+ 'https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
+ 'https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
+ 'https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
+ 'https://d.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png'
+ ],
+ 'tileSize': 256,
+ 'attribution': '© <a target="_top" rel="noopener" href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, © <a target="_top" rel="noopener" href="https://carto.com/attribution">CARTO</a>'
+ }
+ },
+ 'glyphs': 'https://cdn.traccar.com/map/fonts/{fontstack}/{range}.pbf',
+ 'layers': [
+ {
+ 'id': 'simple-tiles',
+ 'type': 'raster',
+ 'source': 'raster-tiles',
+ 'minzoom': 0,
+ 'maxzoom': 22
+ }
+ ]
+ },
+ center: [0, 0],
+ zoom: 1
+});*/
+
+const map = new mapboxgl.Map({
+ container: element,
+ style: {
+ version: 8,
+ sources: {
+ osm: {
+ type: 'raster',
+ tiles: ["https://tile.openstreetmap.org/{z}/{x}/{y}.png"],
+ tileSize: 256,
+ attribution: '© <a target="_top" rel="noopener" href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
+ },
+ },
+ glyphs: 'https://cdn.traccar.com/map/fonts/{fontstack}/{range}.pbf',
+ layers: [{
+ id: 'osm',
+ type: 'raster',
+ source: 'osm',
+ }],
+ },
+});
+
+map.addControl(new mapboxgl.NavigationControl());
+
+map.on('load', () => {
+ loadImage('images/background.svg').then(background => {
+ Promise.all([
+ loadIcon('icon-marker', background, 'images/icon/marker.svg')
+ ]).then(() => {
+ ready = true;
+ if (registeredListener) {
+ registeredListener();
+ registeredListener = null;
+ }
+ });
+ });
+});
+
+export default {
+ element,
+ map,
+ registerListener,
+ addLayer,
+ removeLayer,
+ calculateBounds,
+};