Как по-разному окрашивать сегменты LineString в анимациях Mapbox GL JS - PullRequest
1 голос
/ 09 февраля 2020

Я делаю анимацию, которая показывает, где волки go, основываясь на некоторых исторических данных о воротнике GPS, которые я получил. Код основан на этом примере Mapbox: https://docs.mapbox.com/mapbox-gl-js/example/live-update-feature/

Я хотел бы раскрасить отрезки линии в зависимости от того, было ли это днем ​​или ночью, синим для ночи и красным для дневного. Например:

enter image description here

В период времени 1 волк движется с востока на северо-восток; сейчас ночь, поэтому отрезок синего цвета. В период времени 2 волк движется на северо-восток; это дневное время, поэтому отрезок красного цвета. В период времени 3 волк снова движется на восток-северо-восток; сейчас ночь, так что отрезок снова синий.

Но я не могу заставить работать разные цвета. У меня есть некоторые данные игрушек / примеров:

{ "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": {
"type": "LineString", "coordinates" : [[-112.191833, 57.073668],
[-112.181833, 57.083668],
[-112.181833, 57.073668],
[-112.201833, 57.075668]]} } ], 
"properties": {"daytime" : [0, 1, 1, 0] }}

Есть 4 периода времени, а средние два - дневное время (установлено на 1).

Вот мой код. (Вам нужно вставить ключ вашего mapbox, чтобы он работал):

mapboxgl.accessToken = 'INSERT YOUR MAPBOX KEY HERE';
var map = new mapboxgl.Map({
	container: 'map',
	style: 'mapbox://styles/mapbox/satellite-v9',
	zoom: 0
});

map.on('load', function() {
	// We use D3 to fetch the JSON here to parse and use it separately
	// from GL JS's use in the added source. You can use any request method 
	// that you want.
	d3.json(
		"https://raw.githubusercontent.com/pete-rodrigue/wolves_of_alberta/data_store/wolves_geojson_example.geojson?token=ACEMB42EH5NKZSF24MHPQSS6JFTMU",
		function(err, data) {
			if (err) throw err;
			
			// save full coordinate list for later
			var coordinates = data.features[0].geometry.coordinates;
			// save 1's and 0's for later
			var daynight = data.properties.daytime  
			
			// start by showing just the first coordinate
			data.features[0].geometry.coordinates = [coordinates[0]];
			// THIS NEXT LINE IS ONE PART OF MY FAILED APPROACH:
			data.properties.daytime = ['blue'];   //  set initial color value to blue
			
			// add it to the map
			map.addSource('trace', { type: 'geojson', data: data });
			map.addLayer({
				'id': 'trace',
				'type': 'line',
				'source': 'trace',
				'paint': {
					// THIS WILL WORK FINE
					'line-color': 'orange',   
					// 'line-color': ['to-string', ['get', 'daytime']], //  DOES NOT WORK
					'line-width': 8
				},
				layout: {'line-cap': 'round', 'line-join': 'round'}
			});
			
			// setup the viewport
			map.jumpTo({ 'center': coordinates[0], 'zoom': 13 });
			map.setPitch(30);
			
			// on a regular basis, add more coords from the saved list to update map
			var i = 0;
			var timer = window.setInterval(function() {
				if (i < coordinates.length) {
					data.features[0].geometry.coordinates.push(
						coordinates[i]
					);
					
					// if it's daytime, append blue; if it's nighttime, append red
					if (daynight[i] == 0) {
						data.properties.daytime.push(['blue']);
					} else {data.properties.daytime.push(['red']);}
				
				map.getSource('trace').setData(data);
				map.panTo(coordinates[i]);
				i++;
			} else {
				window.clearInterval(timer);
			}
		}, 150);
	}
);
});
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
<head>
<meta charset="utf-8" />
<title>Wolves GPS collar example data</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://api.mapbox.com/mapbox-gl-js/v1.7.0/mapbox-gl.js"></script>
<script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v1.7.0/mapbox-gl.css" rel="stylesheet" />
<link rel="stylesheet" href="main_css.css">
</head>

<body>
  <div id="map"></div>
  <script type="text/javascript" src='main_js.js'></script>
</body>

Также здесь: https://codepen.io/pete-rodrigue/pen/XWbJOpK

Я прокомментировал часть, которая не была работает и оставил записку.

В основном я пытаюсь сделать это:

'line-color': ['to-string', ['get', 'daytime']]

в paint части map.addLayer(), где свойство daytime является массив строк с надписью «синий» или «красный», на которые я добавляю sh новых элементов в процессе анимации - вот эта часть кода:

if (daynight[i] == 0) {
   data.properties.daytime.push(['blue']);  // if it's daytime, append blue
 } else {
   data.properties.daytime.push(['red']);  // if it's nighttime, append red
 }

Я уверен, что есть Очевидная причина, почему это не работает. Но я новичок в этом и не могу этого понять.

Любая помощь и объяснение основ будет высоко ценится.

1 Ответ

1 голос
/ 26 марта 2020

Когда вы указываете:

'line-color': ['to-string', ['get', 'daytime']]

в слое 'trace' с Map#addLayer, рендереру карт говорят использовать '[0, 1, 1, 0]' (в случае предоставленных вами примеров данных) как цвет линий в source с идентификатором 'trace'. Он не ждет, пока вы настроите таймер, и даже если это произойдет, вы, скорее всего, столкнетесь с некоторыми проблемами с асинхронностью JavaScript. Как отмечено в спецификации стиля Mapbox , 'line-color' ожидает color в форме шестнадцатеричных значений в стиле HTML, RGB, RGBA, HSL или HSLA, так что вы скорее всего, возникают ошибки, поскольку строковый массив не относится ни к одной из этих форм.

Вместо этого я бы рекомендовал разбивать каждый период времени на свой собственный LineString, где 'line-color' определяется его соответствующим значением в исходный массив цветов и добавление этих LineString s на карту в виде отдельных слоев. Затем вы можете создать эффект анимации, установив некоторые интервалы, чтобы указать порядок, в котором слои должны быть добавлены и анимированы, как это сделано в примере Live Update .

...