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

Движок разрабатывался без использования каких-либо специализированных библиотек или фреймворков. Единственная используемая библиотека – jQuery.
Изображения карт – тайлы – сгенерированы с помощью нашей утилиты. Тут еще есть к чему стремиться, так как их оптимизацией мы еще не занимались.
Все отрисовывается на CANVAS’e, за исключением таких элементов как панель дополнительных инструментов и popup’ов меток (хотя в демо по ссылке ниже их все равно нет).
Реализация модульная и состоит из следующих основных частей, назначение которых думаю понятно из их названий: CanvasDragger, CanvasEventer, CanvasImgLoader, CanvasMapper, CanvasMarker, CanvasMiniMapper, CanvasResizer, CanvasTools, CanvasZoomer.
Для того чтобы подключить карты достаточно в нужном месте html’a написать следующую строчку:
Далее в коде JS производим инициализацию (как пример):
Остановимся поподробнее на параметрах:
Или что скрывается за тем или иным действием пользователя. Пройдемся по основным событиям.
При инициализ��ции карт рассчитывается количество тайлов, которое нужно показать, чтобы полностью покрыть canvas. Зная размеры canvas’a, при заданном размере тайлов в 256х256, проделываем данную операцию.
Далее когда происходит движение карты – dragg – проверяем ситуацию если мы передвинули карту на такое расстояние, что нужно подгрузить новый тайл. Так же проверяем все ли тайлы находятся в области видимости, если нет, то запускается «сборщик мусора»:
При срабатывании события “mousewheel” последовательно происходят следующие основные действия:
Работа проверялась в FireFox, Chrome, Safari, Opera и IE последних версий.
Для тех кто все еще не в курсе лишний раз подчеркну следующее. Так как используется canvas, автоматически отпадают все браузеры, не поддерживающие данную технологию, а это — IE версии 8 и ниже и совсем уж старые версии вышеперечисленных браузеров.
1. Уменьшение размеров тайлов карты (должно дать ощутимый прирост скорости работы);
2. Слайдер изменения масштаба;
3. Инструмент получения информации по точке на карте (адрес здания, координаты и тп);
4. ???
Демо: share.arkada-sw.ru/canvasmap

Общие сведения
Движок разрабатывался без использования каких-либо специализированных библиотек или фреймворков. Единственная используемая библиотека – 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
