summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wray <jason@mapbox.com>2018-07-16 12:19:18 -0400
committerJason Wray <jason@mapbox.com>2018-11-27 14:39:29 -0500
commitc7f9f1582f39115e3b05c89e8c253f258515f112 (patch)
treef05e04f2e6dab74d01c688dccd29571fda5198f8
parentf772a6392db1f24a8fbfd0a120de87fd96e51921 (diff)
downloadqtlocation-mapboxgl-c7f9f1582f39115e3b05c89e8c253f258515f112.tar.gz
[ios] Add frame duration graph view to iosapp
-rw-r--r--platform/ios/app/MBXFrameTimeGraphView.h11
-rw-r--r--platform/ios/app/MBXFrameTimeGraphView.m140
-rw-r--r--platform/ios/app/MBXViewController.m23
-rw-r--r--platform/ios/app/Main.storyboard27
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj6
5 files changed, 198 insertions, 9 deletions
diff --git a/platform/ios/app/MBXFrameTimeGraphView.h b/platform/ios/app/MBXFrameTimeGraphView.h
new file mode 100644
index 0000000000..9c3f6f8c32
--- /dev/null
+++ b/platform/ios/app/MBXFrameTimeGraphView.h
@@ -0,0 +1,11 @@
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface MBXFrameTimeGraphView : UIView
+
+- (void)updatePathWithFrameDuration:(CFTimeInterval)frameDuration;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/ios/app/MBXFrameTimeGraphView.m b/platform/ios/app/MBXFrameTimeGraphView.m
new file mode 100644
index 0000000000..f689768818
--- /dev/null
+++ b/platform/ios/app/MBXFrameTimeGraphView.m
@@ -0,0 +1,140 @@
+#import "MBXFrameTimeGraphView.h"
+
+const CGFloat MBXFrameTimeExaggeration = 4.f * 1000.f;
+const CGFloat MBXFrameTimeBarWidth = 4.f;
+
+@interface MBXFrameTimeGraphView ()
+
+@property (nonatomic) CAScrollLayer *scrollLayer;
+@property (nonatomic) CAShapeLayer *thresholdLayer;
+@property (nonatomic) CGFloat currentX;
+@property (nonatomic) NSMutableArray<CAShapeLayer *> *barLayers;
+
+@property (nonatomic) UIColor *safeColor;
+@property (nonatomic) UIColor *warningColor;
+@property (nonatomic) UIColor *dangerColor;
+
+@end
+
+@implementation MBXFrameTimeGraphView
+
+- (instancetype)init {
+ if (self = [super init]) {
+ [self commonInit];
+ }
+ return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder {
+ if (self = [super initWithCoder:aDecoder]) {
+ [self commonInit];
+ }
+ return self;
+}
+
+- (void)commonInit {
+ self.userInteractionEnabled = NO;
+ self.layer.opacity = 0.9f;
+
+ self.scrollLayer = [CAScrollLayer layer];
+ self.scrollLayer.scrollMode = kCAScrollHorizontally;
+ self.scrollLayer.masksToBounds = YES;
+ [self.layer addSublayer:self.scrollLayer];
+
+ self.thresholdLayer = [CAShapeLayer layer];
+ self.thresholdLayer.fillColor = [UIColor darkGrayColor].CGColor;
+ [self.layer addSublayer:self.thresholdLayer];
+
+ self.barLayers = [NSMutableArray array];
+
+ self.safeColor = [UIColor colorWithRed:(CGFloat)(0.f/255.f) green:(CGFloat)(190.f/255.f) blue:(CGFloat)(123.f/255.f) alpha:1.f];
+ self.warningColor = [UIColor colorWithRed:(CGFloat)(255.f/255.f) green:(CGFloat)(154.f/255.f) blue:(CGFloat)(82.f/255.f) alpha:1.f];
+ self.dangerColor = [UIColor colorWithRed:(CGFloat)(255.f/255.f) green:(CGFloat)(91.f/255.f) blue:(CGFloat)(86.f/255.f) alpha:1.f];
+}
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+
+ if (!CGRectEqualToRect(self.scrollLayer.frame, self.bounds)) {
+ self.scrollLayer.frame = self.bounds;
+
+ CGRect thresholdLineRect = CGRectMake(0, self.frame.size.height - [self renderDurationTargetMilliseconds], self.frame.size.width, 1);
+ self.thresholdLayer.path = CGPathCreateWithRect(thresholdLineRect, nil);
+ }
+}
+
+- (void)updatePathWithFrameDuration:(CFTimeInterval)frameDuration {
+ [CATransaction begin];
+ [CATransaction setDisableActions:YES];
+
+ self.currentX += MBXFrameTimeBarWidth;
+
+ CAShapeLayer *bar = [self barWithFrameDuration:frameDuration];
+ bar.position = CGPointMake(self.currentX, self.frame.size.height);
+
+ [self.scrollLayer addSublayer:bar];
+ [self.barLayers addObject:bar];
+
+ [self.scrollLayer scrollToPoint:CGPointMake(self.currentX - self.frame.size.width, 0)];
+
+ [self removeStaleBars];
+
+ [CATransaction commit];
+}
+
+- (CGFloat)renderDurationTargetMilliseconds {
+ CGFloat maximumFramesPerSecond;
+ if (@available(iOS 10.3, *)) {
+ maximumFramesPerSecond = UIScreen.mainScreen.maximumFramesPerSecond;
+ } else {
+ // Not always strictly accurate, but works as an expedient approximation.
+ maximumFramesPerSecond = 60;
+ }
+
+ CGFloat target = (1.0 / maximumFramesPerSecond) * MBXFrameTimeExaggeration;
+ return [self roundedFloat:target];
+}
+
+- (CGFloat)roundedFloat:(CGFloat)f {
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ CGFloat scaleFactor = [UIScreen mainScreen].nativeScale;
+#elif TARGET_OS_MAC
+ CGFloat scaleFactor = [NSScreen mainScreen].backingScaleFactor;
+#endif
+ return round(f * scaleFactor) / scaleFactor;
+}
+
+- (CAShapeLayer *)barWithFrameDuration:(CFTimeInterval)frameDuration {
+ CAShapeLayer *bar = [CAShapeLayer layer];
+
+ CGRect barRect = CGRectMake(0, 0, MBXFrameTimeBarWidth, -(fminf(frameDuration * MBXFrameTimeExaggeration, self.frame.size.height)));
+ UIBezierPath *barPath = [UIBezierPath bezierPathWithRect:barRect];
+ bar.path = barPath.CGPath;
+ bar.fillColor = [self colorForFrameDuration:frameDuration].CGColor;
+
+ return bar;
+}
+
+- (UIColor *)colorForFrameDuration:(CFTimeInterval)frameDuration {
+ CGFloat renderDurationTargetMilliseconds = [self renderDurationTargetMilliseconds];
+ frameDuration *= MBXFrameTimeExaggeration;
+
+ if (frameDuration < renderDurationTargetMilliseconds && frameDuration > (renderDurationTargetMilliseconds * 0.75)) {
+ return self.warningColor;
+ } else if (frameDuration > renderDurationTargetMilliseconds) {
+ return self.dangerColor;
+ } else {
+ return self.safeColor;
+ }
+}
+
+- (void)removeStaleBars {
+ if (self.barLayers.count > (self.frame.size.width / MBXFrameTimeBarWidth * 3)) {
+ NSRange staleBarsRange = NSMakeRange(0, self.frame.size.width / MBXFrameTimeBarWidth);
+ NSArray *staleBars = [self.barLayers subarrayWithRange:staleBarsRange];
+ [staleBars makeObjectsPerformSelector:@selector(removeFromSuperlayer)];
+ [self.barLayers removeObjectsInRange:staleBarsRange];
+ }
+}
+
+@end
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index f058b75dc9..856e4de481 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -8,6 +8,8 @@
#import "LimeGreenStyleLayer.h"
#import "MBXEmbeddedMapViewController.h"
+#import "MBXFrameTimeGraphView.h"
+
#import <Mapbox/Mapbox.h>
#import "../src/MGLMapView_Experimental.h"
@@ -95,6 +97,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MBXSettingsMiscellaneousWorldTour,
MBXSettingsMiscellaneousRandomTour,
MBXSettingsMiscellaneousShowZoomLevel,
+ MBXSettingsMiscellaneousShowFrameTimeGraph,
MBXSettingsMiscellaneousScrollView,
MBXSettingsMiscellaneousToggleTwoMaps,
MBXSettingsMiscellaneousLocalizeLabels,
@@ -192,14 +195,17 @@ CLLocationCoordinate2D randomWorldCoordinate() {
@property (nonatomic) IBOutlet MGLMapView *mapView;
@property (weak, nonatomic) IBOutlet UIButton *hudLabel;
+@property (weak, nonatomic) IBOutlet MBXFrameTimeGraphView *frameTimeGraphView;
@property (nonatomic) NSInteger styleIndex;
@property (nonatomic) BOOL debugLoggingEnabled;
@property (nonatomic) BOOL customUserLocationAnnnotationEnabled;
@property (nonatomic, getter=isLocalizingLabels) BOOL localizingLabels;
@property (nonatomic) BOOL reuseQueueStatsEnabled;
@property (nonatomic) BOOL mapInfoHUDEnabled;
+@property (nonatomic) BOOL frameTimeGraphEnabled;
@property (nonatomic) BOOL shouldLimitCameraChanges;
@property (nonatomic) BOOL randomWalk;
+
@end
@interface MGLMapView (MBXViewController)
@@ -238,6 +244,7 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
self.mapView.showsScale = YES;
self.mapView.showsUserHeadingIndicator = YES;
+ self.mapView.experimental_enableFrameRateMeasurement = YES;
self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
if ([MGLAccountManager accessToken].length)
@@ -293,6 +300,7 @@ CLLocationCoordinate2D randomWorldCoordinate() {
[defaults setBool:self.mapView.showsUserLocation forKey:@"MBXShowsUserLocation"];
[defaults setInteger:self.mapView.debugMask forKey:@"MBXDebugMask"];
[defaults setBool:self.mapInfoHUDEnabled forKey:@"MBXShowsZoomLevelHUD"];
+ [defaults setBool:self.mapInfoHUDEnabled forKey:@"MBXShowsFrameTimeGraph"];
[defaults synchronize];
}
@@ -323,6 +331,7 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.mapInfoHUDEnabled = YES;
[self updateHUD];
}
+ self.frameTimeGraphEnabled = [defaults boolForKey:@"MBXShowsFrameTimeGraph"];
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
@@ -452,6 +461,7 @@ CLLocationCoordinate2D randomWorldCoordinate() {
@"Start World Tour",
@"Random Tour",
[NSString stringWithFormat:@"%@ Map Info HUD", (_mapInfoHUDEnabled ? @"Hide" :@"Show")],
+ [NSString stringWithFormat:@"%@ Frame Time Graph", (_frameTimeGraphEnabled ? @"Hide" :@"Show")],
@"Embedded Map View",
[NSString stringWithFormat:@"%@ Second Map", ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")],
[NSString stringWithFormat:@"Show Labels in %@", (_localizingLabels ? @"Default Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])],
@@ -681,6 +691,12 @@ CLLocationCoordinate2D randomWorldCoordinate() {
[self updateHUD];
break;
}
+ case MBXSettingsMiscellaneousShowFrameTimeGraph:
+ {
+ self.frameTimeGraphEnabled = !self.frameTimeGraphEnabled;
+ self.frameTimeGraphView.hidden = !self.frameTimeGraphEnabled;
+ break;
+ }
case MBXSettingsMiscellaneousScrollView:
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
@@ -2224,7 +2240,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
}
hudString = [NSString stringWithFormat:@"Visible: %ld Queued: %ld", (unsigned long)self.mapView.visibleAnnotations.count, (unsigned long)queuedAnnotations];
} else if (self.mapInfoHUDEnabled) {
- if (!self.mapView.experimental_enableFrameRateMeasurement) self.mapView.experimental_enableFrameRateMeasurement = YES;
hudString = [NSString stringWithFormat:@"%.f FPS (%.1fms) ∕ %.2f ∕ ↕\U0000FE0E%.f° ∕ %.f°",
roundf(self.mapView.averageFrameRate), self.mapView.averageFrameTime,
self.mapView.zoomLevel, self.mapView.camera.pitch, self.mapView.direction];
@@ -2281,4 +2296,10 @@ CLLocationCoordinate2D randomWorldCoordinate() {
return features;
}
+- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered {
+ if (self.frameTimeGraphEnabled) {
+ [self.frameTimeGraphView updatePathWithFrameDuration:mapView.frameTime];
+ }
+}
+
@end
diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard
index 3e8a0ad02a..f4e535a56c 100644
--- a/platform/ios/app/Main.storyboard
+++ b/platform/ios/app/Main.storyboard
@@ -1,14 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
- <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
- <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
- <capability name="Navigation items with more than one left or right bar item" minToolsVersion="7.0"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -42,12 +39,25 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</button>
+ <view hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BHE-Wn-x69" customClass="MBXFrameTimeGraphView">
+ <rect key="frame" x="0.0" y="467" width="375" height="200"/>
+ <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+ <accessibility key="accessibilityConfiguration">
+ <accessibilityTraits key="traits" notEnabled="YES"/>
+ </accessibility>
+ <constraints>
+ <constraint firstAttribute="height" constant="200" id="TgT-yb-9e5"/>
+ </constraints>
+ </view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<gestureRecognizers/>
<constraints>
<constraint firstItem="58y-pX-YyB" firstAttribute="top" secondItem="kNe-zV-9ha" secondAttribute="topMargin" constant="30" id="89S-qk-mPR"/>
+ <constraint firstItem="BHE-Wn-x69" firstAttribute="leading" secondItem="kNe-zV-9ha" secondAttribute="leading" id="aHd-3F-9nV"/>
+ <constraint firstAttribute="bottom" secondItem="BHE-Wn-x69" secondAttribute="bottom" id="bfH-4q-2uU"/>
<constraint firstItem="58y-pX-YyB" firstAttribute="leading" secondItem="kNe-zV-9ha" secondAttribute="leadingMargin" id="cXU-Qh-ilW"/>
+ <constraint firstAttribute="trailing" secondItem="BHE-Wn-x69" secondAttribute="trailing" id="lZL-gi-2XC"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="58y-pX-YyB" secondAttribute="trailing" id="txU-Gp-2du"/>
</constraints>
<connections>
@@ -104,6 +114,7 @@
</rightBarButtonItems>
</navigationItem>
<connections>
+ <outlet property="frameTimeGraphView" destination="BHE-Wn-x69" id="sFg-9b-DgH"/>
<outlet property="hudLabel" destination="58y-pX-YyB" id="aGG-7a-bZR"/>
<outlet property="mapView" destination="kNe-zV-9ha" id="VNR-WO-1q4"/>
<segue destination="zvf-Qd-4Ru" kind="show" identifier="ShowSnapshots" id="hzX-Jp-UJq"/>
@@ -117,7 +128,7 @@
</connections>
</pongPressGestureRecognizer>
</objects>
- <point key="canvasLocation" x="1365.5999999999999" y="349.13793103448279"/>
+ <point key="canvasLocation" x="1365.5999999999999" y="348.57571214392806"/>
</scene>
<!--Offline Packs-->
<scene sceneID="xIg-PA-7r3">
@@ -279,7 +290,7 @@
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Rotation" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vio-XU-tgS">
- <rect key="frame" x="209.5" y="6" width="50.5" height="16"/>
+ <rect key="frame" x="209" y="6" width="50.5" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="50.5" id="OiV-2P-9xm"/>
</constraints>
@@ -294,7 +305,7 @@
</connections>
</switch>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Pitch" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0uK-zq-Ys2">
- <rect key="frame" x="312" y="6" width="31" height="16"/>
+ <rect key="frame" x="312.5" y="6" width="31" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="31" id="gM8-I7-4d3"/>
</constraints>
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index f0ddbb346d..160d82bcf9 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -359,6 +359,7 @@
9654C1261FFC1AB900DB6A19 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */; };
9654C1291FFC1CCD00DB6A19 /* MGLPolygon_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1271FFC1CC000DB6A19 /* MGLPolygon_Private.h */; };
9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */; };
+ 965DF51120F9430500438AAC /* MBXFrameTimeGraphView.m in Sources */ = {isa = PBXBuildFile; fileRef = 965DF51020F9430500438AAC /* MBXFrameTimeGraphView.m */; };
966FCF4C1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */; };
966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; };
966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; };
@@ -1047,6 +1048,8 @@
9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolyline_Private.h; sourceTree = "<group>"; };
9654C1271FFC1CC000DB6A19 /* MGLPolygon_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolygon_Private.h; sourceTree = "<group>"; };
9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewScaleBarTests.m; sourceTree = "<group>"; };
+ 965DF50F20F9430500438AAC /* MBXFrameTimeGraphView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXFrameTimeGraphView.h; sourceTree = "<group>"; };
+ 965DF51020F9430500438AAC /* MBXFrameTimeGraphView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MBXFrameTimeGraphView.m; sourceTree = "<group>"; };
9660916B1E5BBFD700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
9660916C1E5BBFD900A9A03B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
9660916D1E5BBFDB00A9A03B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -1875,6 +1878,8 @@
1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */,
DA1DC9531CB6C1C2006E619F /* MBXViewController.h */,
DA1DC99A1CB6E064006E619F /* MBXViewController.m */,
+ 965DF50F20F9430500438AAC /* MBXFrameTimeGraphView.h */,
+ 965DF51020F9430500438AAC /* MBXFrameTimeGraphView.m */,
632281DD1E6F855900D75A5D /* MBXEmbeddedMapViewController.h */,
632281DE1E6F855900D75A5D /* MBXEmbeddedMapViewController.m */,
DA821D051CCC6D59007508D4 /* Main.storyboard */,
@@ -2952,6 +2957,7 @@
files = (
DA1DC9971CB6E046006E619F /* main.m in Sources */,
354B839C1D2E9B48005D9406 /* MBXUserLocationAnnotationView.m in Sources */,
+ 965DF51120F9430500438AAC /* MBXFrameTimeGraphView.m in Sources */,
DA1DC9991CB6E054006E619F /* MBXAppDelegate.m in Sources */,
DA1DC96B1CB6C6B7006E619F /* MBXOfflinePacksTableViewController.m in Sources */,
DA1DC96A1CB6C6B7006E619F /* MBXCustomCalloutView.m in Sources */,