Leaflet 1.x.x vs Openlayers 4.x.x. Часть 1. Исходный код

    Хочу поделиться опытом работы с данными JS-картографическими фреймворками, надеюсь материалы помогут сделать выбор в вопросе: какую библиотеку использовать именно в вашем проекте. Чтобы не утомлять, разобью его на несколько логических частей. Начнем с основного и исходного — кода.


    Мне всегда нравился код Openlayers 2, он был максимально академично написан и документирован, разобраться в его коде и стать соавтором или написать плагин было достаточно легко.

    Код 3-й версии и последующих также хорошо написан и документирован, но есть одно «но» — написан с использованием Google Closure Compiler и без использования ES6. Это весьма занятная штука, вот, например, размер самих библиотек:
    Фреймворк Сборка Исходные файлы
    Leaflet 1.0.3 144 кб 410 кб (90 файлов)
    Openlayers 4.1.1 511 кб 3.1 мб (300 файлов)

    Видно, что Сlosure Сompiler в 2+ раза эффективней сжимает исходные файлы, чем механизм Leaflet. Также предоставляет удобный механизм использования пространств имен при разработке, а не «эти ваши» import ‘../../../../src’ в ES6.

    На этом все преимущества Google Closure заканчиваются (мое субъективное мнение). Дальше начинаются некоторые страдания, связаны они в основном с тем, что в сборках имена всех членов класса кроме публичных «оптимизируются» до 1-2 букв. Например, вам нужно написать потомок класса ol.source.Image под ваш источник данных, и вы можете работать только с публичными свойствами и методами. Достучаться до приватных членов класса, как и до абстрактных классов родителей, будет проблематично. Есть только один внятный вариант — делать свои сборки Openlayers (авторы OL предлагают использовать именно этот вариант), а делать плагины «рядом», не влезая в основную библиотеку, получится не очень удобно. Однако, внутри сборки Openlayers есть почти все что нужно для создания гис, даже сторонние провайдеры векторных и растровых данных (Esri например), и вероятность написания чего-либо самому или поиск плагина для большинства систем достаточно мала.

    Leaflet изначально задумывался по другому принципу. В самой библиотеке есть необходимый минимум, для всего остального — плагины. Код следует этому принципу. В начале он был правда не очень документирован, комментариев не было совсем, потом появились заглавия в каждом классе, сейчас уже для всех публичных методов и свойств класса есть образцово-показательные описания и примеры использования. Код написан с использованием ES6 (пока используется только модульная система). Соответсвенно максимально удобно как создавать свои сборки Leaflet, так и писать расширения для него, авторы рекомендуют последнее.

    В статье хотел показать простой пример доработки одного и второго фреймоворка на примере создания тайлового слоя с нестандартной тайловой сеткой, точка отсчета тайлов не в левом-верхнем углу, а посередине сетки (да, и такое встречается). Для Leaflet плагин выглядел примерно бы так:

    export var CenterOriginTileLayer = TileLayer.extend({
      getTileUrl: function (coords) {
        // здесь идут простые математические действия по сдвигу координат тайла в центр сетки
        // и возвращание URL для данного тайла
      }
    });
    

    Но тут я внезапно понял, что для тайлового источника (ol.source.XYZ) в Openlayers есть свойство типа ol.tilegrid.TileGrid, в котором, в свою очередь, есть свойство origin — те самые координаты центра сетки. Короче говоря, в Openlayers есть все, и кодить даже не пришлось бы.

    Итак, если оценивать с точки зрения кода, при прочих равных, что выбрать? Если вы понимаете, что и в Openlayers и в Leaflet (+плагины) нет готового, нужного вам функционала и придется засучив рукава писать дополнения или даже делать кастомную сборку — выбирайте Leaflet. Он проще и его легче интегрировать в ваш проект. Если функционала и там и там вам хватает, то в вопросе выбора надо руководствоваться другими условиями.

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

    Подробнее
    Реклама
    Комментарии 16
    • +2
      Достучаться до приватных членов класса, как и до абстрактных классов родителей, будет проблематично

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

      • +1
        В рамках обычных ООП-шных языков вы будете правы. Но в JS технически все члены класса публичные, и разделение их на приватные, защищенные и публичные условно. В OL у некоторых свойств ( в комментах к ним для jsdoc) стоит модификатор protected — т.е. доступ из потомков предполагается. Я не говорю здесь про доступ из других классов к приватным методам и свойствам, я говорю про доступ из потомков.
        • 0

          Мне кажется, что если разработчик использует нотацию приватных членов (в Closure или в Typescript), то он воспринимает отсутсвие в js приватных свойств, как недостаток и решает его с помощью компилятора/транспайлера. Скрытие данных или реализации с помощью приватных свойств и методов даёт разработчику преимущество не думать об обратной совместимости, когда он захочет их поменять.


          Насчёт @protected не понял, там в коде есть @protected и @private у одних и тех же свойств? Я думаю, что это ошибка.

          • 0
            Из потомков нельзя достучаться даже до членов классов которые помечены как protected, т.е. предполагается доступ к ним.
            • 0

              Я код OpenLayers не модифицировал, но с Closure Compiler/Library работал плотно, и у меня этой проблемы не было. Возможно, есть какие-то особенности, про которые я не знаю.

              • 0
                Вот вы-то мне и нужны ))) Может быть я что-то не понимаю, вам вопрос: могу ли я нормально наследоваться с доступом к членам protected и абстрактным классам, если код уже собран? и работаю я с ним уже после Closure Compiler.
                • 0

                  Я все такие телодвижения делал до сборки, так что не смогу помочь, к сожалению. И использовал Closure как программист-пользователь, т.е. не настраивал окружение.


                  Если вы это будете делать средствами javascripta, то, думаю, сможете. Ведь собранный код — это javascript, и там нет @protected, @abstract, @private и т.д.


                  Лично я на вашем месте попробовал бы typescript, с ним должно стать всё намного проще (например, https://stackoverflow.com/a/40732068/8159386)

          • 0

            Во-первых, если из-за технических ограничений разработчик не может сделать настоящий приватный член, и поэтому просто помечает его, как приватный, он как раз и имеет в виду, что полагаться на него нельзя и вообще трогать его нельзя. Так что желание достучаться до приватных членов класса — всё ещё странное.


            Во-вторых в JS технически нет проблем с тем, чтобы сделать приватные члены класса. И добраться до них, в отличии от какой-нибудь джавы, будет вообще нереально.

            • 0
              Под словом «приватные», я больше имел ввиду не публичные.
              Простой пример по коду Leaflet.
              Есть класс Layer, у него есть свойство _map, судя по "_" оно не публичное.
              Есть класс наследник — LayerGroup, он использует свойство this._map от потомка. Т.е. по сути своей оно защищенное (protected), объявлено как приватное, но фактически оно публичное, т.к. к нему можно обратится извне.
              • 0
                Т.е. по сути своей оно защищенное (protected)

                Так и есть.


                объявлено как приватное

                Что вы имеете в виду, когда говорите, что оно объявлено, как приватное? Что у него underscore перед именем?


                но фактически оно публичное

                Я хотел отметить, что в js нет проблем с тем, чтобы сделать его приватным фактически.

        • +2
          Только разогнался и статья закончилась, эх. Можно было и побольше, зачем делить на столь мелкие.
          • 0
            Согласен с вами, но последующие 2 статьи про плагины, фишки и выводы будут объемней, а моя лень затянет написание такой длинной статьи на бесконечное время. Поэтому решил подробить. Сейчас думаю: может еще рассказать как рендеры у них работают.
            • 0
              Буду ждать, интересная тема.
          • +2
            Лично я не вижу для себя весомых преимуществ в «академичности» OL. Это совершенно абстрактное достоинство, которое на практике выливается в банальную многословность. На каждый чих у них объект, каждый объект нужно конструировать.

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

            Код
            // Leaflet
            var map1 = L.map('map1', {
                center: [55.8, 37.6],
                zoom: 12,
            });
            L.tileLayer('http://sometileserver.com/{z}/{x}/{y}.png', {
                attribution: '© <a href="http://sometileserver.com">sometileserver.com</a>',
            })
            .addTo(map1);
            
            // OpenLayers
            var map2 = new ol.Map({
                target: 'map2',
                layers: [
                    new ol.layer.Tile({
                        source: new ol.source.XYZ({
                            url: 'http://sometileserver.com/{z}/{x}/{y}.png',
                            attributions: new ol.Attribution({
                                html: '© <a href="http://sometileserver.com">sometileserver.com</a>',
                            }),
                        }),
                    })
                ],
                view: new ol.View({
                    center: ol.proj.fromLonLat([37.6, 55.8]),
                    zoom: 12,
                }),
            });
            

            Я имел дело (понемногу) почти со всеми популярными картографическими апи — имхо, Leaflet рулит и бибикает.
            • +1
              Ну это пока вы в «мейнстриме» держитесь, а как только шаг вправо, шаг влево, начинаются нюансы. Возьмите коническую проекцию, да разных плагинов, которые друг с другом не работают, вот тут Леафлет бибикая уезжает в кювет, но об этом в следующий раз. Так что, не все так однозначно.
              • 0

                <сарказм>Меркаатора хватит для всего</сарказм>

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