Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
vik
8 лет назад

Скрипт местоположения пользователей голоса на Google Map (Урок+Демо) и почему важна стандартизация данных в профиле и постах

Совместив JS API голоса и GoogleMaps удалось сделать интересный плагин, который своим примером может задать вектор для идей разработки и еще на один шаг приблизит голос к росту собственной экосистемы и взаимодействию со множеством сервисов.

 

Демо работы скрипта доступно на странице https://golos.rubtc.info/usermap/

Исходник можно взять тут https://github.com/vikxx/golos/blob/master/usermap.html

Исходники и инструкцию как создать такое на своем хостинге или локально в браузере я напишу ниже, но сначала лирическое отступление ко второй части заголовка "почему важна стандартизация, валидация и здравая логика данных в голосе".

Если вы заметили, на карте всего несколько человек. Это первые попавшиеся пользователи с корректно заполненным полем профиля "Место нахождения", а изначальная идея плагина была чуть более полезнее простого отображения чек-инов адуитории:

Первоночальная суть идеи была в том, что бы отобразить местоположения делегатов, а именно города серверов их нод.

Это бы помогло будущим делегатам правильно раположить свою ноду (локацию сервера) основываясь на существующей широте покрытия, говоря простым языком - чем ближе нода территориально к пользователю, тем быстрее она работает. Кроме того, такое наглядное отображение нод в реальном времени может участвовать в качестве хорошего промо-материала для инвесторов и просто привлечения новых пользователей. Но все разбилось о то, что поле местоположения заполнено всего у нескольких делегатов. И даже эти несколько заполнили в свойственной творческим людям манере :) Например "Планета Земля", "Млечный Путь" или "Въ Блокчейне", таким образом, если брать эти данные для геотагов, то кого-то вполне может отобразить в стрип-баре под названием в "Млечный Путь" (Хотя, в контексте @siski и молочных желез вполне себе истина :). Плюнув на делегатов, я решил посмотреть среди обычных пользователей, но и там нашлось много фантазеров впихнувшых невпихуемое в местоположение, пришлось для примера выбрать только несколько случайных человек с корректными данными.

Валидация данных, чем раньше, тем лучше. 

По собственному опыту могу уверенно заявить - чем раньше команда сделает жесткую валидацию РАЗНЫХ данных от пользователей, тем лучше. Т.е. если имеем поле для местоположения - там должна быть возможность вабрать и указать из списка определенный город, а в случае ввода произвольного текста - не принимать данные. Такую же практику нужно применять к любой новой официальной фиче для клиента. Если не делать это своевременно, то планы на будущее разработчиков из мыслей о развитии превратятся в рутинные миграции БД и форматирование мусорных данных.   

Но еще больше пользы от стандартизации данных - это дружелюбность API голоса, которая позволит сторонним разработчикам строить на основе блокчейна голоса настолько гибкие приложения, что голос вырастет из блогов в основу всего RU блокчейна. 

Создание плагина для отображения местоположения пользователей

Скрипт который я буду описывать ниже выполняет следующую задачу:

Берется массив аккаунтов пользователей, далее из каждого аккаунта мы берем содержимое поля "место нахождения", после используя Google Maps мы выводим все местоположения на карте, подписывая маркеры логинами и краткой информацией из профиля.  


Для работы скрипта нам нужно оформить html страницу и подключить необходимые библиотеки, а именно:

  • Jquery
  • API Google Maps
  • Адаптация Steemjs.com для голоса ( github.com/ontofractal/golosjs)

https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js
https://maps.googleapis.com/maps/api/js
https://golos.rubtc.info/g.js

 

Не забываем в html странице оставить div элемент, куда будут грузиться карты

google-container

Я опущу описание косметической части, которая отвечает за цветовую палитры самой карты. В двух словах - стилизуем цвета и убираем не нужные элементы с карты так, что бы она выглядела под стать вашему цветовому оформлению. Для этого поместим все стили в переменную, которую укажем позднее в вызове карты.

Этот кусок кода можно пропустить:

Переходим к основной части скрипта

Как писал выше, наш список имен я выбрал случайно, основаясь на том, что пользователь заполнил правильно поле местоположения, мы будем рассматривать этот в ручную прописанный список, но в конце поста опишу как сделать выборку пользователей автоматически и по разным критериям.

Итак, помещаем наших ребят в массив names:

 var names =['vood.one','alexna','kuna','dr2073','dhrms','zaria','ropox','radomir']; 

 Прописываем ряд глобальных переменных, которые будем использовать из разных функций и циклов

var geocoder,map,infowindow,i,marker,address = [],icon=[],username=[];

Описываем и наполняем базовыми параметрами функцию инициализации Google карты

initialize();
  function initialize() {
    geocoder = new google.maps.Geocoder();
    infowindow = new google.maps.InfoWindow();
    var latlng = new google.maps.LatLng(56.0251514,37.0447503);
    var mapOptions = {
      center: latlng,
      zoom: $map_zoom,
        panControl: false,
        zoomControl: false,
        mapTypeControl: false,
        streetViewControl: false,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        styles: style
    }
    map = new google.maps.Map(document.getElementById("google-container"), mapOptions);
  }

Карта пока что пустая, в качестве центра указана Москва, отключены всякие гугловские свистелки, в параметр styles мы вставили наши ранее описанные цветовые стили, пустую карту вывели в div с id google-container.

Теперь нужно отметить на карте пользователей из массива выше. Для этого нам нужно пройтись по их аккаунтам и собрать все поля с местоположениями, что бы это сделать, мы будем использовать websocket API голоса/стима ( https://steemjs.com/ )

Воспользуемся вызовом getAccounts, в котором укажем наш массив с именами names

steem.api.getAccounts(names, function(err, result) {
  var count = 0;
  for (i = 0; i < result.length; i++) {

// Тут будем проставлять маркеры на карту

}

Внутри цикла у нас появятся данные аккаунтов выбранных пользователей и нам нужно их рассортировать по переменным и массивам

 var metas = JSON.parse(result[i].json_metadata); // Получаем json_metadata из каждого аккаунта
 username.push(result[i].name); // Получаем имена аккаунтов
 address.push(metas.profile.location); // Массив с содержимым поля "местоположение"
 icon.push(metas.profile.profile_image); // Аватарки

Данные готовы, в username у нас список имен, address - то что написано в поле местоположения, icon - аватарки. 

Вывод пользователей на карту возможен благодря функционалу геокодинга

https://developers.google.com/maps/documentation/javascript/geocoding 

Маркер в любом случае будет выводится на основе широты и долготы, но так как пользователи не указывают широту и долготу, нам придется вычислять ее на стороне гугла геокодингом. В этом есть свои минусы - если у пользователя в строке местоположения указан бред - гугл найдет ближайший по смыслу бред на карте и укажет его координаты. Например если у пользователя указано в местоположении "на деревне у бабушки", гугл поставит маркер на найденом объекте по своему усмотреннию и едва ли это отразит идею как пользователя, так и веб-сервиса. Потому хотелось бы, что бы в клиенте была жестко указанно, в каком фомате указывать данные.

Ищем широту и долготу указанных пользователями данных с помощью функции geocode

geocoder.geocode( {'address': address[i]}, function(results, status) {

Мы находимся в цикле, потому в address у нас будет свое значение для каждого из пользователей. Из этого значения гугл получит широту и долготу с помощью results[0].geometry.location и мы укажем это в параметры position куда и следует прописывать широту с долготой для маркеров.

 

geocoder.geocode( {'address': address[i]}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
      var marker = new google.maps.Marker({
            map: map,
        visible: true,
        label: username[count],
        icon:'https://golos.io/images/favicons/favicon.ico',
            position: results[0].geometry.location
        });
    }count++
    });

Кроме этого у нас есть label - надпись на маркере - подпишем их именами пользователей.

Icon - это иконки маркера, возьмем favico голоса. 

Так же мы сделаем так, что бы при нажатии на маркер открывалось больше информации об авторе:

var infowindow = new google.maps.InfoWindow({content:'Какой-то текст связанный с автором'})

Вместо какого-то текста мы выведем данные, которые будут выглядеть вот так:

Выведем аватар, ник и локацию. Локацию для того, что бы было понятно, насколько верно геокодер гугла понял значение пользователя. То есть если гугл неправильно поставил маркер, мы сможем увидеть, что имел в ввиду пользователь в своем поле и почему гугл решил отметить в какой-то локации.

Вывод данных в инфобокс сделаем так:

content: '<img src="'+icon[count]+'"/> @'+username[count]+' указал локацию: '+address[count]

И повесим на событие нажатия на маркер функцию раскрытия инфобокса

marker.addListener('click', function() {infowindow.open(map, marker);});

 

Еще немного косметических функций, в которых стилизуем кнопки зума под расцветку голоса:

function CustomZoomControl(controlDiv, map) {
        var controlUIzoomIn= document.getElementById('cd-zoom-in'),
            controlUIzoomOut= document.getElementById('cd-zoom-out');
        controlDiv.appendChild(controlUIzoomIn);
        controlDiv.appendChild(controlUIzoomOut);
        google.maps.event.addDomListener(controlUIzoomIn, 'click', function() {
            map.setZoom(map.getZoom()+2)
        });
        google.maps.event.addDomListener(controlUIzoomOut, 'click', function() {
            map.setZoom(map.getZoom()-1)
        });
    }
    var zoomControlDiv = document.createElement('div'),
    zoomControl = new CustomZoomControl(zoomControlDiv, map);
    map.controls[google.maps.ControlPosition.LEFT_TOP].push(zoomControlDiv);

Готово! 

Теперь мы видим местоположение пользователей на карте.

Не всех, а только тех, которых указали сами: var names =['vood.one','alexna','kuna','dr2073','dhrms','zaria','ropox','radomir'];

Вывести других/всех/по виду/репутации и т.д. можно обращаясь к разным вызовам API steemjs.com, но главная загвоздка в том, что мало-кто правильно указывает данные в профиле. Надеюсь это исправится со временем, тогда можно будет получать список имен разными способами

В качестве примера - получим всех делегатов в порядке рейтинга их нод:

steem.api.getWitnessesByVote('', 100, function(err, result) {
var names =[];
for (var i = 0; i < result.length; i++){
names.push(result[i].owner);
 }
}

Теперь в нашем names делегаты. И просто используем names как в основном примере.

 

Или можем использовать lookup и найти например 1000 пользователей, юзернэйм которых похож на ник siski

steem.api.lookupAccounts('siski', 1000, function(err, result) {
names.push(result[i].name);
});

 

В заключение

Некоторые речевые обороты в посте могут заставить вас думать, что я подговариваю вас указывать реальные данные местоположения в блокчейне, что в некотором роде претит идеалогии децентрализации. Но на самом деле я призываю к другому - помогать развитию голоса создавая новые точки входа для разработчиков на блокчейн. В чем-то опередить стим, в чем-то не отставать от глобальных трендов.

Не забывайте, что благополучие каждого автора зависит от благополучия всей сети голоса!

3
2245.293 GOLOS
На Golos с January 2017
Комментарии (15)
Сортировать по:
Сначала старые