Интерактивное представление пространственных данных с помощью прокрутки
Рассказывать истории и идеи с помощью интерактивных карт
Об этой статье
Эта статья о карте-истории, которую я создал:
…и эта статья – рассказ о том, как я его построил.
Введение
Продукт картографа — это карты. Мы работаем с шейп-файлами (которые являются наследием хранения пространственных данных), базами геоданных, geojson и многими формами пространственных данных и используем ГИС для создания карт из них. Эти карты, однако, часто представляют собой документы в формате JPEG, PNG или PDF, которые не являются интерактивными. В большинстве случаев да, это работает, но мне нравится рассказывать и мне рассказывают истории, когда мне не нужно делать большую часть работы. С меньшими усилиями, как я могу рассказывать истории?
Затем я наткнулся на статью Кутберта Чоу о D3.js. D3.js — это библиотека javascript для управления элементами и svg в DOM (объектная модель документа). Люди используют D3.js для представления данных, в которых Чоу провел великолепную демонстрацию, расширив статью Джима Валландингема. Посмотрите на его следующую статью.
И тут до меня дошло: мы можем сделать это и с картами! Идея прокрутки и интерактивного представления данных возможна с использованием javascript. В этой статье рассказывается о том, как я это сделал.
Вы можете найти живую демонстрацию здесь:
Стеки
Все ресурсы данных и карт имеют открытый исходный код (openstreetmap). Ниже приведены стеки, которые я использовал
- jquery и d3.js: работа с документами
- leaflet.js: интерактивная веб-карта
Общая идея
Я пишу о науке о пространственных данных и написал статью о представлении пространственных данных в следующей статье. Эта статья является демонстрацией.
По сути, идея того, как это работает, такова:
- Использование Python для получения и анализа пространственных данных.
- Использование HTML для разметки документов, CSS для придания красоты; представление содержания.
- Использование Javacript для интерактивности. В этом случае меняем карты при прокрутке.
Дополнительно (не в этой статье/проекте) мы можем что-то сделать с источниками данных:
- Хранение данных на сервере базы данных postgresql + postgis.
- Apache Airflow для организации/автоматического сбора данных и заполнения сервера базы данных.
- Использование геосервера в качестве внутреннего картографического сервера.
Возможно, для будущих проектов.
Как это работает
Подробности рассказывать не буду, а то статья получится очень длинной. То, что я объясню, — это идея высокого уровня, которую разработчики должны… разрабатывать.
Большая часть кода взята из статьи Джима о скроллере javascript. Демо на основе этого кода доступно здесь.
Но в этой статье я обсуждаю свою демонстрацию. Я разобью его на основе этих компонентов:
- Макет
- Разделы и прокрутка
- Хранилище данных
Макет — исправление карты
Вёрстка основана на модуле Bootstrap 5 css. Это очень распространенный модуль, который быстро украшает HTML. Он предоставляет необходимые минимальные компоненты пользовательского интерфейса.
В частности, я сделал 2 столбца, как показано на следующем изображении. Серый — это фон тела, синий — поля, а белый/светлый — фон столбца.
<div class="container"> <div class="row"> <div class="col-4"> the first column, text contents / stories </div> <div class="col-8"> the second wider column where the map is going to live </div> </div> </div>
Я хочу, чтобы прокрутка была интерактивной с историей/текстом, но не с картой. Это означает, что карту нужно фиксировать независимо от того, сколько мы прокручиваем. Здесь на помощь приходит css. Все, что игнорирует прокрутку, требует фиксированной позиции, поэтому я создал класс stay
css.
.stay { position: fixed; height: 100%; width: 100% }
и вставьте его в div
, где будет жить карта.
<div class="col-8"> <!-- the second wider column where the map is going to live. --> <div class="stay" id="mapcontainer"> <div id="map" ></div> </div> </div>
Таким образом, карта div
будет исправлена.
Карты и Javascript
поскольку карта div
создана, теперь мы можем импортировать leaflet
библиотеку javascript для создания наших карт. Leaflet
предоставляет инструменты интерактивности карты, которые мне нужны. Это блестящий пакет; так просто, но это работает!
var map = L.map('map').setView([51.505, -0.09], 13); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map); L.marker([51.5, -0.09]).addTo(map) .bindPopup('A pretty CSS3 popup.<br> Easily customizable.') .openPopup();
Разделы и прокрутка
Как и структура Чоу и Джима, страница «Прибытие в Лондон» также состоит из разделов с идентификатором step
.
<div class="col-4 full "> <section class="step "> my first section </section> <section class="step "> the second section </section> <section class="step "> and so on </section> <section class="step "> ... </section> </div>
Интерактивная прокрутка
После того, как шаги определены, документ должен отслеживать активность пользователя при прокрутке. Следующий код вызывает функцию trackPosition
каждый раз, когда пользователь прокручивает страницу.
d3.select(window) .on("scroll.scroller", trackPosition);
trackPosition
выглядит следующим образом:
// sectionsArray are the div step (s) from the HTML that we previously defined let activeSection; let previousSection; const trackPosition = ()=>{ let pos = window.pageYOffset - 140; let sectionIndex = d3.bisect(sectionPositions, pos); sectionIndex = Math.min(sections.size() - 1, sectionIndex); activeIndex = sectionIndex if (sectionsArray[sectionIndex] !== activeSection){ previousSection = activeSection activeSection = sectionsArray[sectionIndex] d3.select(`#${activeSection}`) .transition() .style("opacity", "1"); d3.select(`#${previousSection}`) .transition() .style('opacity', '0.2') ; positionMap(sectionIndex) } }
Обратите внимание на функцию positionMap
! Эта функция заставляет карту изменяться.
// positionMap: changes the map based on the active step const positionMap = (sectionIndex) =>{ if (sectionIndex === 0){ map.flyTo([51.505404,-0.118658], 9,) // zoom in to coords airportLayer.addTo(map) // leaflet layer elizaebthLine_st.remove() // leaflet layer popupairport() // popup the map attractions.remove() // leaflet layer } if (sectionIndex === 1){ map.flyTo([51.509687,-0.115464], 13,) // zoom in to coords attractions.addTo(map) // leaflet layer attractions.eachLayer((l)=>{l.openTooltip()}) // open the tooltips // add another if and manually code the interactivity. Read the leaflet documentation. }
Хранилище данных
В структуру данных без схемы, которая в основном представляет собой массив, содержащий объекты JSON, мы можем добавлять произвольные свойства. Я демонстрирую это в статье о структуре данных.
Мы можем определить пространственные данные как минимум следующим образом:
// minimum spatial data const berlin = { "city": "berlin", "country": "germany", "location" : { "type" : "Point", "coordinates": [52.507650, 13.410298] } }
Но я ограничиваюсь спецификацией пространственных данных GeoJSON, поэтому пространственные данные выглядят так:
const attractions_geojson = { "type": "FeatureCollection", "features": [ { // minimum spatial data but with geojson spec "type": "Feature", "properties": { "name": "big ben" }, "geometry": { "coordinates": [ -0.12466064329075266, 51.50067738052945 ], "type": "Point" } }, { // minimum spatial data but with geojson spec "type": "Feature", "properties": { "name": "leicester square" }, "geometry": { "coordinates": [ -0.13047682089788282, 51.51079955591317 ], "type": "Point" } } ] }
attractions_geojson.features
, содержащий наши слои, в приведенном выше коде состоит из 2 слоев: Биг Бен и Лестер-сквер. geojson.features
— это список всех минимальных пространственных данных.
Вы можете просмотреть пространственные данные в variable.js
при загрузке демонстрационной ссылки в браузере.
Заключение
Используя Javascript и HTML, мы можем сделать наши данные интерактивными. Как картограф, это означает, что я могу сделать свои карты интерактивными и отзывчивыми! Хитрость заключается в том, чтобы хранить пространственные данные в виде файла javascript вместо обычного шейп-файла и объекта geojson.