Better blending of adjacent lines on map
This commit is contained in:
		
							parent
							
								
									a5aa58d2ee
								
							
						
					
					
						commit
						37a9a1bd72
					
				
							
								
								
									
										144
									
								
								front/map.js
								
								
								
								
							
							
						
						
									
										144
									
								
								front/map.js
								
								
								
								
							| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
require('ol/ol.css');
 | 
					require('ol/ol.css');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const axios = require('axios');
 | 
				
			||||||
const {Map, View} = require('ol');
 | 
					const {Map, View} = require('ol');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const TileLayer = require('ol/layer/Tile').default;
 | 
					const TileLayer = require('ol/layer/Tile').default;
 | 
				
			||||||
| 
						 | 
					@ -17,47 +18,77 @@ const proj = require('ol/proj');
 | 
				
			||||||
const {Style, Fill, Stroke, Circle} = require('ol/style');
 | 
					const {Style, Fill, Stroke, Circle} = require('ol/style');
 | 
				
			||||||
const color = require('color');
 | 
					const color = require('color');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapboxToken = 'pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJjazUxaWNsdXcwdWhjM2\
 | 
					const mapboxToken = `pk.eyJ1IjoibWF0dGVvZGVsYWJyZSIsImEiOiJja2NxaTUyMmUwcmFhMn\
 | 
				
			||||||
9tc2xndXJoNGtxIn0.xELwMerqJLFimIqU6RxnZw';
 | 
					h0NmFsdzQ3emxqIn0.cyxF0h36emIMTk3cc4VqUw`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const server = window.origin;
 | 
					const server = window.origin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const fetchDataSources = async () =>
 | 
					const fetchDataSources = async () =>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const dataSource = new VectorSource();
 | 
					    const segmentsSource = new VectorSource();
 | 
				
			||||||
 | 
					    const stopsSource = new VectorSource();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const res = await fetch(`${server}/network`);
 | 
					    const network = (await axios.get(`${server}/network`)).data;
 | 
				
			||||||
    const network = await res.json();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const stopPoints = Object.entries(network.stops)
 | 
					    segmentsSource.addFeatures(
 | 
				
			||||||
        .map(([stopId, stop]) =>
 | 
					        Object.values(network.lines).flatMap(({color, routes}) =>
 | 
				
			||||||
            new Feature({
 | 
					 | 
				
			||||||
                type: 'stop',
 | 
					 | 
				
			||||||
                color: network.lines[stop.lines[0]].color,
 | 
					 | 
				
			||||||
                geometry: new Point(proj.fromLonLat([stop.lon, stop.lat])),
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dataSource.addFeatures(stopPoints);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const segmentLines = Object.values(network.lines)
 | 
					 | 
				
			||||||
        .flatMap(({color, routes}) =>
 | 
					 | 
				
			||||||
            routes.map(({segments}) =>
 | 
					            routes.map(({segments}) =>
 | 
				
			||||||
                new Feature({
 | 
					                new Feature({
 | 
				
			||||||
                    type: 'segment',
 | 
					 | 
				
			||||||
                    color,
 | 
					                    color,
 | 
				
			||||||
                    geometry: new LineString(segments.flat().map(
 | 
					                    geometry: new LineString(segments.flat().map(
 | 
				
			||||||
                        ({lat, lon}) => proj.fromLonLat([lon, lat])
 | 
					                        ({lat, lon}) => proj.fromLonLat([lon, lat])
 | 
				
			||||||
                    )),
 | 
					                    )),
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        );
 | 
					        )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dataSource.addFeatures(segmentLines);
 | 
					    stopsSource.addFeatures(
 | 
				
			||||||
 | 
					        Object.entries(network.stops).map(([stopId, stop]) =>
 | 
				
			||||||
 | 
					            new Feature({
 | 
				
			||||||
 | 
					                color: network.lines[stop.lines[0]].color,
 | 
				
			||||||
 | 
					                geometry: new Point(proj.fromLonLat([stop.lon, stop.lat])),
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return dataSource;
 | 
					    return {segmentsSource, stopsSource};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const makeBorderColor = mainColor =>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const hsl = color(mainColor).hsl();
 | 
				
			||||||
 | 
					    hsl.color = Math.max(0, hsl.color[2] -= 20);
 | 
				
			||||||
 | 
					    return hsl.hex();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const segmentsBorderStyle = feature => new Style({
 | 
				
			||||||
 | 
					    stroke: new Stroke({
 | 
				
			||||||
 | 
					        color: makeBorderColor(feature.get('color')),
 | 
				
			||||||
 | 
					        width: 8,
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const segmentsInnerStyle = feature => new Style({
 | 
				
			||||||
 | 
					    stroke: new Stroke({
 | 
				
			||||||
 | 
					        color: feature.get('color'),
 | 
				
			||||||
 | 
					        width: 6,
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const stopsStyle = feature => new Style({
 | 
				
			||||||
 | 
					    image: new Circle({
 | 
				
			||||||
 | 
					        fill: new Fill({
 | 
				
			||||||
 | 
					            color: feature.get('color'),
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					        stroke: new Stroke({
 | 
				
			||||||
 | 
					            color: makeBorderColor(feature.get('color')),
 | 
				
			||||||
 | 
					            width: 1.5,
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					        radius: 6,
 | 
				
			||||||
 | 
					    }),
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const createMap = async (target) =>
 | 
					const createMap = async (target) =>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    // Map background
 | 
					    // Map background
 | 
				
			||||||
| 
						 | 
					@ -74,54 +105,31 @@ const createMap = async (target) =>
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Data overlay
 | 
					    // Data overlay
 | 
				
			||||||
    const dataSource = await fetchDataSources();
 | 
					    const {segmentsSource, stopsSource} = await fetchDataSources();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const makeBorderColor = mainColor =>
 | 
					    const segmentsBorderLayer = new VectorLayer({
 | 
				
			||||||
    {
 | 
					        source: segmentsSource,
 | 
				
			||||||
        const hsl = color(mainColor).hsl();
 | 
					        style: segmentsBorderStyle,
 | 
				
			||||||
        hsl.color = Math.max(0, hsl.color[2] -= 20);
 | 
					 | 
				
			||||||
        return hsl.hex();
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const dataLayer = new VectorLayer({
 | 
					 | 
				
			||||||
        source: dataSource,
 | 
					 | 
				
			||||||
        updateWhileInteracting: true,
 | 
					        updateWhileInteracting: true,
 | 
				
			||||||
        updateWhileAnimating: true,
 | 
					        updateWhileAnimating: true,
 | 
				
			||||||
        style: feature =>
 | 
					    });
 | 
				
			||||||
        {
 | 
					
 | 
				
			||||||
            if (feature.get('type') === 'stop')
 | 
					    const segmentsInnerLayer = new VectorLayer({
 | 
				
			||||||
            {
 | 
					        source: segmentsSource,
 | 
				
			||||||
                return new Style({
 | 
					        style: segmentsInnerStyle,
 | 
				
			||||||
                    image: new Circle({
 | 
					
 | 
				
			||||||
                        fill: new Fill({
 | 
					        updateWhileInteracting: true,
 | 
				
			||||||
                            color: feature.get('color'),
 | 
					        updateWhileAnimating: true,
 | 
				
			||||||
                        }),
 | 
					    });
 | 
				
			||||||
                        stroke: new Stroke({
 | 
					
 | 
				
			||||||
                            color: makeBorderColor(feature.get('color')),
 | 
					    const stopsLayer = new VectorLayer({
 | 
				
			||||||
                            width: 2,
 | 
					        source: stopsSource,
 | 
				
			||||||
                        }),
 | 
					        style: stopsStyle,
 | 
				
			||||||
                        radius: 6,
 | 
					
 | 
				
			||||||
                    }),
 | 
					        minZoom: 13,
 | 
				
			||||||
                });
 | 
					        updateWhileInteracting: true,
 | 
				
			||||||
            }
 | 
					        updateWhileAnimating: true,
 | 
				
			||||||
            else if (feature.get('type') === 'segment')
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                return [
 | 
					 | 
				
			||||||
                    new Style({
 | 
					 | 
				
			||||||
                        stroke: new Stroke({
 | 
					 | 
				
			||||||
                            color: makeBorderColor(feature.get('color')),
 | 
					 | 
				
			||||||
                            width: 8,
 | 
					 | 
				
			||||||
                        }),
 | 
					 | 
				
			||||||
                    }),
 | 
					 | 
				
			||||||
                    new Style({
 | 
					 | 
				
			||||||
                        stroke: new Stroke({
 | 
					 | 
				
			||||||
                            color: feature.get('color'),
 | 
					 | 
				
			||||||
                            width: 6,
 | 
					 | 
				
			||||||
                        }),
 | 
					 | 
				
			||||||
                    }),
 | 
					 | 
				
			||||||
                ];
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Setup map
 | 
					    // Setup map
 | 
				
			||||||
| 
						 | 
					@ -129,7 +137,9 @@ const createMap = async (target) =>
 | 
				
			||||||
        target,
 | 
					        target,
 | 
				
			||||||
        layers: [
 | 
					        layers: [
 | 
				
			||||||
            backgroundLayer,
 | 
					            backgroundLayer,
 | 
				
			||||||
            dataLayer,
 | 
					            segmentsBorderLayer,
 | 
				
			||||||
 | 
					            segmentsInnerLayer,
 | 
				
			||||||
 | 
					            stopsLayer,
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        view: new View({
 | 
					        view: new View({
 | 
				
			||||||
            center: proj.fromLonLat([3.88, 43.605]),
 | 
					            center: proj.fromLonLat([3.88, 43.605]),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue