Permalink
372 lines (279 sloc) 32.1 KB

Содержание

  1. Как принять участие в развитии API карт
  2. Как разработать собственный модуль
  3. Как внести изменения в исходный код
  4. Установка локальной сборки API карт
  5. Стандарты кодирования

Как принять участие в развитии API карт

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

Расскажите о нас

Реализовали качественный проект на API 2ГИС? Напишите об этом в своем блоге или социальной сети, поделитесь своим опытом использования API с другими разработчиками.

Сообщайте об ошибках

Если вы нашли ошибку в работе API карт или столкнулись с проблемой, сообщите об этом на форуме обратной связи и мы обязательно поможем вам разобраться с проблемой. Как правило, хорошо локализованная ошибка — это уже половина работы по её исправлению, потому постарайтесь сделать максимально простой пример, на котором воспроизводится ошибка и разместите его в публичном доступе (например, используя JSFiddle), также не забудьте указать версию браузера и ОС, чтобы мы смогли воспроизвести ошибку.

Разрабатывайте собственные модули

Вы можете расширять функциональность API карт под свои потребности при помощи модулей. Прочтите небольшую инструкцию, которая поможет написать ваш первый модуль. Если считаете, что модуль будет полезен другим разработчикам, обязательно сообщите нам об этом по адресу api@2gis.ru, мы разместим информацию о нем на официальном сайте 2ГИС, а возможно и включим в базовую поставку API карт.

Участвуйте в исправлении ошибок

Вы можете самостоятельно исправить найденные ошибки в работе API карт, для этого необходимо ознакомиться с процессом внесения изменений в исходный код и прислать нам pull request.

Участвуйте в улучшении документации

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

  • найти интересующий вас раздел документации в папке src/doc/ и открыть его содержимое;
  • нажать кнопку Edit, отредактировать текст документации и нажать кнопку Propose File Change.

Мы рассмотрим ваш pull request с изменениями и при следующем релизе после их принятия они появятся на сайте API 2ГИС.

Как разработать собственный модуль

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

Перед началом разработки рекомендуется ознакомиться со стандартами кодирования и документацией API карт.

Инициализация

Первое, что необходимо сделать — это создать отдельный Github-репозиторий для нашего модуля.

И сформировать файловую структуру:

/src   - исходные JS файлы
/demo  - HTML файлы с примерами использования
/dist  - минифицированные JS и CSS файлы, а также изображения
README.md
LICENSE.md

Код модуля

Так как наш модуль довольно простой, он будет состоять всего из одного исходного JS файла, назовем его DGDemoPlugin.js и напишем в нем необходимый для работы код:

    DG.DemoPlugin = DG.Handler.extend({

       _lastFirms: DG.layerGroup(),

       addHooks: function() {
           this._map.on('click', this._searchFirms, this);
       },

       removeHooks: function() {
           this._map.off('click', this._searchFirms, this);
       },

       _searchFirms: function(e) { // (MouseEvent)
           var latlng = e.latlng.wrap();

           DG.ajax({
               url: 'http://catalog.api.2gis.ru/2.0/search',
               data: {
                   what: 'магазин',
                   point: latlng.lng + ',' + latlng.lat,
                   radius: 500,
                   page_size: 50,
                   type: 'filial',
                   key: '12345678'
               },
               success: DG.bind(this._showFirms, this),
               error: DG.bind(this._logError, this)
           });
       },

       _showFirms: function(data) { // (Object)
           var firms, marker;

           if (data.response.code > 200) {
               this._logError(data);
               return;
           }

           this._lastFirms.clearLayers();

           firms = data.result.data;
           firms.forEach(function(firmInfo) {
               marker = DG.marker([firmInfo.geo.lat, firmInfo.geo.lon]);
               marker.bindPopup(firmInfo.firm.name);
               marker.addTo(this._lastFirms);
           }, this);

           this._lastFirms.addTo(this._map);
       },

       _logError: function(data) {
           console.log('Error: ', data);
       }
   });

   DG.Map.addInitHook('addHandler', 'demoPlugin', DG.DemoPlugin);

Наш модуль предполагает взаимодействие пользователя с картой, потому мы его отнаследовали от класса DG.Handler. Благодаря этому можно будет контролировать его поведение в процессе исполнения приложения (например, у разработчика будет возможность включить или выключить модуль).

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

Методы addHooks и removeHooks срабатывает в тот момент, когда разработчик конечного приложения включает или отключает наш модуль.

Метод _searchFirms отправляет AJAX-запрос к REST API справочника 2ГИС и в случае успешного ответа вызывает метод _showFirms.

Метод _showFirms удаляет с карты все предыдущие маркеры и показывает новые.

Метод _logError при возникновении ошибки печатает в консоль браузера данные о ней.

Конструкция DG.Map.addInitHook('addHandler', 'demoPlugin', DG.DemoPlugin) позволяет карте зарегистрировать написанный нами обработчик пользовательских действий, после чего к нему можно будет обратиться по соответствующему имени, например:

map.demoPlugin.enable();

Минификация и подключение

Для минификации JS файлов существует множество популярных инструментов, вы можете воспользоваться любым из них, напрмиер YUI Compressor. Минифицированный JS файл необходимо положить в папку dist и предоставить к нему публичный доступ, после чего любой разработчик сможет подключить и использовать его вместе с API карт. Пример подключения модуля:

DG.then(function() {
    //загрузка модуля
    return DG.plugin('https://raw.github.com/2gis/maps-api-2.0-plugin-demo/master/dist/DGDemoPlugin.js');
})
.then(function() {
    //инициализация карты
    var map = new DG.Map('map', {
        'center': new DG.LatLng(54.980206086231, 82.898068362003),
        'zoom': 15,
        'geoclicker': false
    });
    // включение модуля
    map.demoPlugin.enable();
});

Прочие рекомендации

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

Рекомендуемая файловая структура модуля:

/src       — исходные JS файлы
/doc       — документация
/lang      — языковые файлы
/skin      — изображения и CSS файлы разных тем API карт
/templates — шаблоны
/test      — тесты
/demo      — HTML файлы с примерами использования
/dist      — минифицированные JS и CSS файлы, а также изображения
README.md
LICENSE.md

В качестве примера модуля с описанной выше файловой структурой можно изучить DGGeoclicker.

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

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

Составьте и положите в корневую папку модуля файл README.md, в котором будут описаны возможности модуля и примеры его использования.

Выберите лицензию для своего модуля, ведь это неотъемлемая часть любого open-source проекта. Такие ресурсы, как tldrlegal.com и opensource.org могут вам в этом помочь.

Как внести изменения в исходный код

Для внесения изменений в существующий исходный код API карт (например, для исправления ошибки) вам потребуется:

  • сделать форк репозитория API карт;
  • установить API карт локально на своем компьютере;
  • сделать ветку, название которой будет соответствовать сути вашего изменения (ветку необходимо унаследовать от ветки master, так как в ней находится последняя стабильная версия API карт);
  • внести свои изменения в код (рекомендуется следовать принятым стандартам кодирования);
  • прислать нам pull request.

После изучения и тестирования pull request-а мы его примем (возможно с некоторыми доработками), после чего они попадут в релиз и станут доступны всем пользователям API карт.

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

Для запуска тестов в PhantomJS (по умолчанию) необходимо из консоли выполнить команду:

gulp test

Для запуска тестов в браузерах вашей операционной системы укажите названия браузеров с помощью параметров:

gulp test --ff --chrome

Список доступных параметров:

(default)   PhantomJS
--chrome    Chrome
--ff        Firefox
--opera     Opera
--safari    Safari
--ie        IE (только для Windows)

Если вам необходимо выполнить тесты за несколько запусков браузера, то вы можете использовать параметр:

--multiple-chunks

По умолчанию при каждом запуске браузера будут выполняться тесты из 10ти модулей. Изменить это число можно параметром:

--items-in-chunk

Также вы можете проверить код на наличие синтаксических ошибок, для этого необходимо выполнить команду:

gulp lint

Установка локальной сборки API карт

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

  • Склонируйте репозиторий:

      git clone git@github.com:2gis/maps-api-2.0.git mapsapi-folder
    

    Примечание: если вы устанавливаете API карт не с текущего репозитория, а с его форка, тогда не забудьте указать первым параметром команды clone адрес форка вместо адреса репозитория 2ГИС.

  • Установите Node.js

  • Установите зависимости:

      cd ~/mapsapi-folder
      npm install
    
  • Выполните сборку API карт и запуск сервера:

      npm run dev
    

После выполнения описанных выше действий вы сможете открыть в браузере карту по адресу http://127.0.0.1:3000/2.0/

Стандарты кодирования

JavaScript

Основные требования к JavaScript коду обеспечиваются синтаксическим анализатором и описаны в конфигурационом файле ESLint. В процессе разработки мы стараемся придерживаться соглашений, схожими с Airbnb style guide, за исключением соглашений о пробелах и комментариях.

HTML и CSS

Определения

Данные соглашения — набор правил разной степени обязательности исполнения. Используется три степени:

  • обязательно — нарушение правила не имеет смысла либо полностью запрещено. Нарушение должно обсуждаться заранее с командой;
  • должно — нарушение правила возможно при достаточном обосновании. Нарушение можно обсудить постфактум или оставить комментарий в коде;
  • рекомендуется — при прочих равных лучше использовать рекомендованный вариант.

Соглашения являются расширением методологии БЭМ, поэтому используются следующие термины:

  • блок — синоним понятий «плагин», «модуль» — неразрывная независимая часть ветки DOM-дерева (или ветка целиком), и связанных с ней CSS-правил, которая может быть переиспользована на любом проекте, в любом контексте. Блоком так же называется корневой тег такой структуры;
  • элемент — структурная единица блока. Элемент всегда принадлежит одной копии блока. Элемент не имеет смысла вне блока. Элемент не может принадлежать одновременно нескольким блокам, или нескольким копиям одного блока. При движении от элемента вверх по DOM дереву можно встретить любое число других элементов того же блока, либо сам блок. Нельзя встретить элементы других блоков или другие блоки;
  • модификатор — синоним понятия «состояние». Модификатор реализует наследование блоков — когда нам нужен второй блок, очень похожий на первый. Модификатор всегда относится к какому-то конкретному блоку или элементу. У любого блока и элемента может быть несколько модификаторов, по несколько значений у каждого.

Область применения

Данное соглашение применяется для вновь создаваемых блоков (модулей). Сюда относится замена блока при рефакторинге. Соглашение имеет слабое влияние при небольших работах со старым кодом, а также при переиспользовании сторонних модулей.

HTML

  • вёрстка должна быть валидным html5 кодом;
  • код должен быть максимально семантичным;
  • код должен быть в нижнем регистре;
  • рекомендуется не указывать типы для тегов script и link;
  • рекомендуется пропускать строку перед блоками, списками, таблицами и т.д.;
  • должны использоваться двойные кавычки в атрибутах HTML.
Рекомендуется использовать теги html5
  • article — выделение смысловой самостоятельной единицы (обычно блока);
  • address — тег для адреса;
  • aside — тег для сопутствующей информации, например «конкуренты»;
  • time — тег для любого времени или даты;
  • header и footer для явно выраженной шапки и футера блока, если такие есть;
  • а также: summary, nav и другие.

Существующие теги и их назначение: http://www.w3.org/TR/html-markup/elements.html#elements

  • рекомендуется использовать атрибуты schema.org;
  • запрещено использовать «табличные» теги: table, thead, tbody, tfoot, tr, th, td кроме как по их прямому назначению — т.е. для отображения табличных данных;
  • запрещено использование устаревших тегов: font, blink и прочее;
  • у каждого тега, который будет иметь визуальное представление на странице, должен быть CSS-класс (полное покрытие тегов классами).
Структура
  • должна использоваться методология БЭМ;
  • любая визуальная HTML нода должна быть покрыта CSS-классом;
  • структура HTML должна быть семантичной и минимально зависеть от дизайна. Иными словами, по HTML-коду должно быть всё понятно о содержимом страницы, но ничего не понятно о её дизайне.

Плохо:

<div class="outer-wrapper">
    <div class="inner-wrapper">
        <div class="right clerafix">Какой-то <span class="red">текст</span></div>
    </div>
</div>

Хорошо:

<article class="dg-card dg-card_type_org dg-card_spec_edu" itemscope itemtype="http://schema.org/EducationalOrganization">
    <header class="dg-card__header">
        <h1 class="dg-card__name" itemprop="name">Школа №176</h1>
    </header>
    <address class="dg-card__address" itemprop="streetAddress">Красный проспект, д. 348</address>
</article>

Приветствуется минимизация DOM-дерева (исключение различных оберток, оболочек, разделителей, однопиксельных GIF-файлов и т.п.).

Общий пример
<div class="dg-board">
    <div class="dg-board__list">
        <div class="dg-filters">...</div>
        <article class="dg-card" itemscope itemtype="http://schema.org/EducationalOrganization">
            <header class="dg-card__header">
                <h1 class="dg-card__name" itemprop="name">Школа №176</h1>
            </header>
            <address class="dg-card__address" itemprop="streetAddress">Красный проспект, д. 348</address>
        </article>
        <article class="dg-card">...</article>
        <article class="dg-card">...</article>
    </div>
</div>

CSS

Именование классов
  • обязательно используется методология БЭМ для именования всех CSS-классов;
  • для блоков должен использоваться префикс .dg-, например: .dg-fullscreen;
  • любой CSS-класс должен начинаться с имени блока;
  • любой класс по своему предназначению и правилам составления имени должен быть блоком, элементом, или модификатором;
  • модификатор обязан иметь четкое описание-комментарий;
  • запрещено использовать в имени блока любые символы, кроме a-z, 0-9 и «-», а в качестве первого символа любые, кроме a-z. То же касается составных частей элементов и модификаторов;
  • должны использоваться одинарные кавычки;
  • должны использоваться короткие 16-тиричные числа, когда это возможно (#ffffff → #fff);
  • рекомендуется использовать сокращенные названия свойств CSS;
  • не рекомендуется указывать единицы измерений после нулевых значений. Плохо: margin: 0px 10px; Хорошо: margin: 0 10px;.

Примеры классов блоков: .dg-search, .dg-popup, .dg-card, .dg-firm-list.

  • имя любого элемента обязательно имеет префикс .block__, где «block» — имя блока, которому принадлежит этот элемент.

Примеры классов элементов: .dg-card__name, .dg-search__query, .dg-popup__close.

  • имя модификатора обязательно имеет префикс block_ или block__elem_ и состоит из двух частей: имя модификатора и значение модификатора.

Примеры классов модификаторов:

  • .dg-card_type_firm — тип карточки «фирма»;
  • .dg-search_mode_metro — режим строки поиска «метро»;
  • .dg-popup_state_hidden — состояние коллаута «скрыт»;
  • .dg-board__list_state_minimized — состояние элемента «список» равно «свёрнут».

Модификаторы:

  • любой модификатор обязательно относится только к какому-то конкретному элементу или блоку;
  • разрешено использовать несколько разных модификаторов блока или элемента одновременно (например .dg-card_state_visible и .dg-card_type_building);
  • запрещено использовать несколько разных значений одного модификатора или элемента одновременно (например .dg-card_state_hidden и .dg-card_state_visible).
Селекторы
  • селектор должен состоять только из одного имени класса;
  • селекторы по тегам крайне не желательны;
  • запрещено использовать селекторы по id;
  • одно состояние одного селектора должно встречаться в CSS 0 или 1 раз;
  • селекторы через запятую не желательны. Если такая необходимость сильно выражена, то стоит подумать о создании нового элемента с общими стилями, и его примешиванию к уже существующим в HTML коде;
  • классы должны быть сгруппированы вокруг своего блока в порядке: блок, элементы, модификаторы блока. То есть, в потоке CSS одним выделением можно выделить все стили блока и его элементов;
  • состояния класса должны быть также сгруппированы: класс, его псевдоклассы, его псевдоэлементы;
  • модификаторы блока должны быть сгруппированы по названию модификатора и по его значениям;
  • псевдоэлементы before и after должны отделяться от селектора одинарным двоеточием.
Свойства
  • запрещено использование !important;
  • стили, предназначенные для IE 8, должны находиться в отдельных файлах;
  • файлы со стилями для IE 8 должны иметь суффикс «ie». Пример: dg-fullscreen.ie.less;
  • наличие невалидного CSS должно быть строго обосновано. Используем CSS валидатор;
  • любое неочевидное свойство или значение должно поясняться /* комментарием */ на английском языке.