Pull to refresh

HTML5 Canvas Map — реализация картографического движка

Reading time3 min
Views19K
В рамках большого интерактивного веб-ориентированного проекта (подробнее о котором возможно в другом посте) я занимаюсь разработкой картографического движка, реализованного на HTML5 CANVAS. Его разработка дошла до стадии беты и, с одобрения моего руководства, появилось желание продемонстрировать данные карты широкой публике.

image

Общие сведения


Движок разрабатывался без использования каких-либо специализированных библиотек или фреймворков. Единственная используемая библиотека – jQuery.

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

Все отрисовывается на CANVAS’e, за исключением таких элементов как панель дополнительных инструментов и popup’ов меток (хотя в демо по ссылке ниже их все равно нет).

Реализация


Реализация модульная и состоит из следующих основных частей, назначение которых думаю понятно из их названий: CanvasDragger, CanvasEventer, CanvasImgLoader, CanvasMapper, CanvasMarker, CanvasMiniMapper, CanvasResizer, CanvasTools, CanvasZoomer.

Для того чтобы подключить карты достаточно в нужном месте html’a написать следующую строчку:
<canvas id="map2d"></canvas>

Далее в коде JS производим инициализацию (как пример):
$(function() {
    mWrap = new MapsWrapper({
        mapDivId: "map2d" // тут указываем ID canvas’a, в котором будет рисоваться карта
    });
});

MapsWrapper = function(properties) {
    this.initialize(properties);
};
$.extend(MapsWrapper.prototype, {
    v2DMapDiv                : null,
    v2DMapComponent   : null,

    initialize: function(prop){
        this.v2DMapDiv = prop.mapDivId;
        this.initMap();
    },

    initMap: function(){
        var GlobalParams = {
            staticMapUrl: ["http://gate.looxity.ru:8088/map.html", "http://zain.looxity.ru:8088/map.html", "http://kaph.looxity.ru:8088/map.html"],
            initCrd     : {x: 7445, y: 9925},
            initZoom    : 0.25,
            zoomList    : [1, 0.5, 0.25, 0.1, 0.05, 0.025],
            miniMap     : true,
            tools       : {scaler: true, polygoner: true}
        };
        this.v2DMapComponent = new CanvasMapper (this.v2DMapDiv);
        this.v2DMapComponent.initialize(GlobalParams);
    }
});


Остановимся поподробнее на параметрах:
  • staticMapUrl – хосты, с которых подгружаются тайлы карты
  • initCrd – начальные координаты в проекции Гаусса-Крюгера, в данном случае примерно соответствуют нулевому километру автодорог, что рядом с Манежной площадью.
  • miniMap – подключение модуля миникарты
  • tools – подключение модуля дополнительных инструментов

Внутренняя механика


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

Стартуем

При инициализации карт рассчитывается количество тайлов, которое нужно показать, чтобы полностью покрыть canvas. Зная размеры canvas’a, при заданном размере тайлов в 256х256, проделываем данную операцию.

Двигаемся

Далее когда происходит движение карты – dragg – проверяем ситуацию если мы передвинули карту на такое расстояние, что нужно подгрузить новый тайл. Так же проверяем все ли тайлы находятся в области видимости, если нет, то запускается «сборщик мусора»:
unVisibleTilesCollector: function() {
        for(var cnt = 0; cnt < this.__TILES__.length; cnt++) {
            if( (this.__TILES__[cnt].canvX + this.tileSize) < 0
                || this.__TILES__[cnt].canvX > this.canvas.width
                || this.__TILES__[cnt].canvY > this.canvas.height
                || (this.__TILES__[cnt].canvY + this.tileSize) < 0
                ) {
                this.__TILES__.splice(cnt, 1);
                cnt--;
            }
        }
    }


Масштабируем (zoomIn, zoomOut)

При срабатывании события “mousewheel” последовательно происходят следующие основные действия:
  • копируется текущее положение всех тайлов
$.extend(this.__ANIM_TILES__, this.mapper.__TILES__)

  • средствами canvas’a и с помощью математики происходит уменьшение или увеличение тайлов (в зависимости от того как мы крутим колесико мыши) из копии, сделанной в пп1
for(cnt; cnt < this.animSteps; cnt++){
	            setTimeout(function(){
	                _this.ctx.clearRect(0,0,_this.canvas.width,_this.canvas.height);
	               _this.ctxMarker.clearRect(0,0,_this.canvas.width,_this.canvas.height);
	                animScale += scale*stepScale;
	                _this.drawAllAnimTiles(evt, {
	                    animScale: animScale,
	                    stepCurrNum: Math.round(Math.abs(animScaleStart-animScale)/stepScale),
	                    stepScale: stepScale
	                });
	             }, delay*cnt);
	        }

  • сверху, по мере подгрузки, накладываются новые тайлы, в соответствии с новым масштабом
MapsWrapper.v2DMapComponent.update()


Работа в браузерах


Работа проверялась в FireFox, Chrome, Safari, Opera и IE последних версий.
Для тех кто все еще не в курсе лишний раз подчеркну следующее. Так как используется canvas, автоматически отпадают все браузеры, не поддерживающие данную технологию, а это — IE версии 8 и ниже и совсем уж старые версии вышеперечисленных браузеров.

TODO List по картам


1. Уменьшение размеров тайлов карты (должно дать ощутимый прирост скорости работы);
2. Слайдер изменения масштаба;
3. Инструмент получения информации по точке на карте (адрес здания, координаты и тп);
4. ???

Демо: share.arkada-sw.ru/canvasmap

ps все права на программный код и карты принадлежат компании, в которой я работаю
pps если данная статья возымеет интерес, то следующим моим постом будет описание примера реального использования данных карт
Tags:
Hubs:
Total votes 55: ↑53 and ↓2+51
Comments54

Articles