Карта

Описание: создание карты с временной шкалой, данные для которой загружаются из файла.

Файл «ViewController.h»

#import <MapCharting/MapChart.h>
#import <MapCharting/MapChart2D.h>
#import "MapDataSource.h"
#import "CustomMap.h"
@interface ViewController : UIViewController {
    CustomMap *m_view; // Двумерная карта
    MapDataSource *datasource; // Источник данных карты
}
@end

Файл «ViewController.m»

#import "ViewController.h"
#import <MapCharting/MapTopobase.h>
#import <MapCharting/MapAreaVisual.h>
#import "SolidColorBrush.h"
#import "DataDependency.h"
#import <MapCharting/MapTooltip.h>
#import <MapCharting/MapLabel.h>
#import <MapCharting/MapLegend.h>
#import <MapCharting/MapShape.h>
#import "UIColor+transition.h"
#import <MapCharting/MapLabel.h>
#import <MapCharting/MapChartSign.h>
#import <MapCharting/MapArrow.h>
#import <MapCharting/MapFilledArrow.h>
#import <MapCharting/MapBarVisual.h>
#import <MapCharting/MapPieVisual.h>
#import "UIColor+hex.h"
#import "CustomMap.h"
#import "CustomMapBubblePopoverView.h"
@implementation ViewController
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Загружаем данные из источника
    datasource = [[MapDataSource alloc]initWithFileName:@"data.txt"];
    // Определяем минимальное и максимальное значения данных
    [datasource prepare];
    // Создаём карту на основе загруженных данных
    [self dataSourceFinishedLoadData];
}
// Создаёт карту на основе загруженных данных
- (void)dataSourceFinishedLoadData
{
    // Создаём двумерную карту
    m_view = [[CustomMap alloc] init];
    // Загружаем файл с топоосновой
    NSData *file = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"world.svg" ofType:nil]];
    // Создаём и устанавливаем объект для работы с топоосновой карты
    MapTopobase *topobase = [[MapTopobase alloc] initWithData:file];
    [m_view setTopobase: topobase];
    // Определяем аффинное преобразование, применяемое ко всем областям карты
    [topobase setTransform: CGAffineTransformIdentity];
    [m_view setClipsToBounds:YES];
    // Запрещаем масштабирование карты
    [m_view setZoomEnabled:NO];
    
    // Создаём объект для работы с картографическим показателем
    MapAreaVisual *visual = [[MapAreaVisual alloc] init];
    // Устанавливаем источник данных
    [visual setDataSource: datasource];
    /* Устанавливаем признак того, что параметры заливки фона областей карты
    зависят от источника данных */
    [[visual background] setIsDependent:YES];
    
    // Создаём объект для работы со слоем карты
    MapLayer *layer = [[m_view topobase] rootLayer];
    // Создаём всплывающую подсказку для слоя
    layer.tooltip = [MapTooltip new];
    // Задаём цвета для заливки фона областей слоя карты
    NSArray *colors = [NSArray arrayWithObjects:@"ff462c", @"ebaf36", @"ffd900", @"b1ca40", @"6a8535", nil];
    // Определяем минимальное значение карты
    double value = [datasource minValue];
    // Определяем шаг для шкалы карты
    double step = (datasource.maxValue - datasource.minValue) / [colors count];
    // Определяем соответствие между интервалами шкалы карты и цветами заливки фона областей слоя
    ValueScale *scale = [[ValueScale new] autorelease];
    for (int i = 1; i <[colors count]; i++) {
        value += step;
        [scale.value addObject:[NSNumber numberWithDouble:value]];
        // Определяем цвета для значения «меньше»
        UIColor *lessColor = [UIColor colorWithHex:[colors objectAtIndex:(i - 1)]];
        [scale.less addObject:[SolidColorBrush solidColorBrushWithColor:lessColor]];
        // Определяем цвета для значения «равно» или «больше»
        UIColor *equalColor = [UIColor colorWithHex:[colors objectAtIndex:(i)]];
        [scale.equal addObject:[SolidColorBrush solidColorBrushWithColor:equalColor]];
        [scale.greater addObject:[SolidColorBrush solidColorBrushWithColor:equalColor]];
    }
    // Устанавливаем шкалу карты
    [[visual background] setScale:scale];
    
    // Устанавливаем кисть для заливки фона карты
    [m_view setBackground:[SolidColorBrush solidColorBrushWithColor:[UIColor whiteColor]]];
    // Устанавливаем цвет заголовка карты
    m_view.caption.textColor = [UIColor blackColor];
    
    // Устанавливаем текст подписи для областей слоя карты, для которых отсутствуют данные
    [m_view setNoDataText: NSLocalizedString(@"NO_DATA", nil)];
    // Создаём кисть для заливки областей слоя карты с отсутствующими данными
    SolidColorBrush *brush = [[[SolidColorBrush alloc] init] autorelease];
    // Установим прозрачность кисти
    [brush setOpacity: 0.2];
    // Установим цвет кисти
    brush.color = [UIColor grayColor];
    // Установим данную кисть
    [[[visual background] scale] setNoData: brush];
    
    Thickness th = {0};
    th.top = 20;
    th.bottom = 20;
    // Определяем текст заголовка
    [[m_view caption] setText: NSLocalizedString(@"WORLD_MAP", nil)];
    // Задаём отступ для заголовка
    [[m_view caption] setMargin: th];
    // Определяем параметры шрифта
    [[m_view caption] setFont:[UIFont systemFontOfSize:18]];
    // Используем направление письма слева направо
    [m_view setUsingRightToLeft: NO];
    
    // Получаем легенду карты
    MapLegend *legend = [m_view legend];
    // Устанавливаем шкалу карты
    [legend setValueScale: scale];
    // Выравниваем легенду по центру карты
    [legend setBlockAlignment: NWLegendBlockAlignmentBottomCenter];
    // Устанавливаем отступы для легенды
    Thickness margin = {0,20,0,0};
    [legend setMargin:margin];
    // Устанавливаем цвет текста и параметры шрифта легенды
    [legend setTextColor:[UIColor blackColor]];
    [legend setFont:[UIFont systemFontOfSize:12]];
    // Устанавливаем формат записи интервала «меньше»
    NSString *lessFormat = [NSMutableString stringWithString:NSLocalizedString(@"LESS_FORMAT", nil)];
    [legend setLessFormat:lessFormat];
    // Устанавливаем формат записи интервала «больше»
    NSString *greaterFormat = [NSMutableString stringWithString:NSLocalizedString(@"GREATER_FORMAT", nil)];
    [legend setGreaterFormat:greaterFormat];
    
    // Создаём верхний текст легенды
    MapLabel *header = [[MapLabel new] autorelease];
    [header setText: NSLocalizedString(@"HEADER_TEXT", nil)];
    // Устанавливаем параметры шрифта для текста
    [header setFont: [UIFont systemFontOfSize:14]];
    [header setTextColor:[UIColor blackColor]];
    // Устанавливаем отступы текста
    Thickness headerMargin = {5, 0, 0, 0};
    [header setMargin:headerMargin];
    // Устанавливаем верхний текст для легенды
    [[m_view legend] setHeader:header];
    
    // Устанавливаем форму маркеров для легенды карты
    [legend setMarkerShape: MarkerShapeRectangle];
    // Задаём ориентацию легенды
    [legend setOrientation: NWLegendOrientationFreeVertical];
    // Устанавливаем позицию легенды
    CGPoint pt = {[m_view legend].origin.x, 325};
    [legend setOrigin: pt];
    
    // Получаем временную шкалу
    MapTimeAxis *timeAxis = [m_view timeAxis];
    // Отображаем временную шкалу
    [timeAxis setHidden: NO];
    // Устанавливаем объект, содержащий методы для работы со шкалой
    [timeAxis setDelegate: m_view];
    // Устанавливаем источник данных
    [timeAxis setDataSource:datasource];
    // Настраиваем задержку анимации
    [timeAxis setDelayTime: AnimateTypeSlow];
    // Задаём параметры шрифта для временной шкалы
    [timeAxis setFont:[UIFont fontWithName:@"Arial" size:16]];
    // Задаём минимальное расстояние в точках между двумя соседними делениями оси
    [timeAxis setMinTickSpacing:1.0];
    // Устанавливаем для делений шкалы синий цвет
    [timeAxis setTickColor: [UIColor blueColor]];
    /* Устанавливаем длительность перемещения от одного значения оси
    к другому во время воспроизведения анимации */
    [timeAxis setJumpTime: AnimateTypeNormal];
    // Устанавливаем текущее положение ползунка шкалы
    [m_view.timeAxis setIndex:0];
    // Создаём и отображаем подпись над текущим положением ползунка шкалы
    MapTooltip *caption = [[MapTooltip new] autorelease];
    [caption setVisibility:YES];
    [timeAxis setLabel: caption];
    
    /* Добавляем объект для работы с картографическим показателем
    в массив визуальных элементов, соответствующих дочерним слоям и областям */
    [[layer visuals] addObject: visual];
    // Добавляем слой карты в массив отображаемых слоёв
    [[m_view layers] addObject:layer];
    [self setView:m_view];
}
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    // Устанавливаем новые размеры карты
    struct CGRect frame;
    frame = CGRectMake(0, 0, 375, 470);
    [m_view setFrame:frame];
    // Устанавливаем рамку серого цвета
    [[m_view layer] setBorderColor: [[UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:1] CGColor]];
    [[m_view layer] setBorderWidth: 1.0f];
    
    // Зададим три области слоя карты
    NSMutableArray *shapes = [[NSMutableArray new] autorelease];
    NSArray *shapesIds = [NSArray arrayWithObjects:@"AU", @"RU", @"BR", nil];
    for (NSString *id in shapesIds) {
        MapShape *shape = [[[m_view layers] objectAtIndex:0] shapeWithId:id];
        [shapes addObject:shape];
    }
    /* Отображаем всплывающее окно для области слоя карты «AU»
    с расположением стрелки в правом верхнем углу окна */
    [self showBubblePopoverForShape:[shapes objectAtIndex:0] withOrientation:PopoverArrowRightTop];
    /* Отображаем всплывающее окно для области слоя карты «RU»
    с оптимальным расположением стрелки */
    [self showBubblePopoverForShape:[shapes objectAtIndex:1] withOrientation:NAN];
    /* Отображаем всплывающее окно для области слоя карты «BR»
    с расположением стрелки посередине нижней границы окна */
    [self showBubblePopoverForShape:[shapes objectAtIndex:2] withOrientation:PopoverArrowBottom];
}
// Отображает всплывающие окна для областей слоя карты
-(void)showBubblePopoverForShape:(MapShape *) shape withOrientation:(BubblePopoverViewArrowOrientation) arrowOrientation {
    // Создаём всплывающее окно
    CustomMapBubblePopoverView *popover = [[CustomMapBubblePopoverView new] autorelease];
    // Определяем размеры всплывающего окна
    CGSize contentSize = CGSizeMake(60, 30);
    [popover setContentSize:contentSize];
    // Определяем левую верхную точку данного окна
    CGPoint originPoint = [shape centerPoint];
    // Преобразуем координаты SVG-карты в экранные координаты
    originPoint = [self convertOriginalPointToScreen:originPoint];
    
    // Определяем расположение стрелки всплывающего окна
    if (arrowOrientation == NAN) {
        CGRect baseRect;
        baseRect.origin = originPoint;
        baseRect.size = contentSize;
        // Располагаем стрелку оптимальным образом
        [popover alignArrowForOrigin:originPoint inRect: baseRect];
        } else {
        [popover setArrowOrientation: arrowOrientation];
    }
    
    // Вычисляем и задаём оптимальные размеры и расположение окна
    CGRect frame = [popover computeRectForOrigin:originPoint];
    frame.size = contentSize;
    [popover setFrame:frame];
    // Устанавливаем цвет границы всплывающего окна
    [popover setBorderColor:[UIColor grayColor]];
    // Задаём цвет текста
    [popover setTintColor:[UIColor blackColor]];
    // Устанавливаем цвет фона данного окна
    MapPlaced *placed = [[MapPlaced new] autorelease];
    [placed setBackground:[SolidColorBrush solidColorBrushWithColor:[UIColor lightTextColor]]];
    // Задаём радиус закругления границы окна
    [placed setBorderRadius:12];
    // Устанавливаем толщину его границы
    [placed setBorderThickness:2];
    /* Задаём идентификатор области слоя карты,
    для которой отображается всплывающее окно */
    [placed setID:[shape ID]];
    [popover setPlaced:placed];
    // Отображаем всплывающее окно
    [m_view addSubview:popover];
}
// Преобразует координаты SVG-карты в экранные координаты
- (CGPoint) convertOriginalPointToScreen: (CGPoint) originalPoint {
    CGFloat coef = [m_view boundsWithMargin].size.width / ([m_view pivot].x * 2);
    originalPoint.x *= coef;
    originalPoint.x += 15;
    CGFloat topoCoef = [m_view pivot].y / [m_view pivot].x;
    originalPoint.y *= coef;
    originalPoint.y += ([m_view boundsWithMargin].size.height -
    [m_view boundsWithMargin].size.width * topoCoef)/2;
    originalPoint.y += -4;
    return originalPoint;
}
@end

См. также:

Создание всплывающего окна для карты