-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathTLMapView.m
139 lines (117 loc) · 3.98 KB
/
TLMapView.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//
// TLMapView.m
// TileMap
//
// Created by Nathan Vander Wilt on 8/20/09.
// Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import "TLMapView.h"
#import <QuartzCore/QuartzCore.h>
#import "TLMapProjection.h"
static NSString* TLMapViewKVOContext = @"TLMapView KVO context";
@interface TLMapView ()
- (NSRect)mapBoundsPaddedToFit:(NSRect)proposedBounds;
@end
@implementation TLMapView
@synthesize projection;
@synthesize desiredBounds;
@synthesize mapLayers;
- (void)addMapLayersObject:(id)newMapLayer { [mapLayers addObject:newMapLayer]; }
- (void)removeMapLayersObject:(id)l { (void)l; [self doesNotRecognizeSelector:_cmd]; }
#pragma mark Lifecyle
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
projection = [TLMapProjection new];
desiredBounds = NSMakeRect(-180.0f, -90.0f, 360.0f, 180.0f);
mapLayers = [NSMutableArray new];
[self addObserver:self
forKeyPath:@"desiredBounds"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial)
context:&TLMapViewKVOContext];
[self addObserver:self
forKeyPath:@"frame"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial)
context:&TLMapViewKVOContext];
}
return self;
}
- (void)dealloc {
[self removeObserver:self forKeyPath:@"desiredBounds"];
[self removeObserver:self forKeyPath:@"frame"];
[projection release];
[mapLayers release];
[super dealloc];
}
#pragma mark Observation
- (void)observeValueForKeyPath:(NSString*)keyPath
ofObject:(id)object
change:(NSDictionary*)change
context:(void*)context
{
if (context == &TLMapViewKVOContext) {
if ([keyPath isEqualToString:@"desiredBounds"]) {
/* NOTE: not using self.mapLayers avoids gcc-4.2 "type of accessor does
not match the type of property" error */
for (NSView* mapLayer in [self mapLayers]) {
[mapLayer setNeedsDisplay:YES];
}
}
else if ([keyPath isEqualToString:@"frame"]) {
for (NSView* mapLayer in [self mapLayers]) {
mapLayer.frame = self.bounds;
}
}
}
else {
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}
#pragma mark Map layer handling
- (NSRect)mapBoundsPaddedToFit:(NSRect)proposedBoundsRect {
CGRect proposedBounds = NSRectToCGRect(proposedBoundsRect);
NSView* fitView = self;
CGFloat percentOfFrameWidth = proposedBounds.size.width / fitView.frame.size.width;
CGFloat percentOfFrameHeight = proposedBounds.size.height / fitView.frame.size.height;
CGRect paddedBounds = CGRectNull;
if (percentOfFrameWidth < percentOfFrameHeight) {
// proposedBounds aren't wide enough
CGFloat properWidth = fitView.frame.size.width * percentOfFrameHeight;
CGFloat difference = properWidth - proposedBounds.size.width;
paddedBounds = CGRectInset(proposedBounds, -difference / 2.0f, 0.0f);
}
else if (percentOfFrameHeight < percentOfFrameWidth) {
// proposedBounds aren't high enough
CGFloat properHeight = fitView.frame.size.height * percentOfFrameWidth;
CGFloat difference = properHeight - proposedBounds.size.height;
paddedBounds = CGRectInset(proposedBounds, 0.0f, -difference / 2.0f);
}
else {
paddedBounds = proposedBounds;
}
return NSRectFromCGRect(paddedBounds);
}
- (NSAffineTransform*)drawTransform {
NSRect mapBounds = [self mapBoundsPaddedToFit:(self.desiredBounds)];
NSRect myBounds = self.bounds;
NSAffineTransform* drawTransform = [NSAffineTransform transform];
[drawTransform translateXBy:(myBounds.origin.x)
yBy:(myBounds.origin.y)];
[drawTransform scaleXBy:(myBounds.size.width / mapBounds.size.width)
yBy:(myBounds.size.height / mapBounds.size.height)];
[drawTransform translateXBy:(-mapBounds.origin.x)
yBy:(-mapBounds.origin.y)];
return drawTransform;
}
- (void)registerMapLayer:(NSView*)newMapLayer {
newMapLayer.frame = self.bounds;
[self addSubview:newMapLayer];
}
- (void)addMapLayer:(id)newMapLayer {
[self registerMapLayer:newMapLayer];
[self addMapLayersObject:newMapLayer];
}
@end