首页 > 其他分享 >iOS 缩放等级 Set the Zoom Level of an MKMapView

iOS 缩放等级 Set the Zoom Level of an MKMapView

时间:2023-05-22 20:02:56浏览次数:52  
标签:Set Level double self 缩放 zoom zoomLevel MERCATOR level



Set the Zoom Level of an MKMapView



http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/



If you have ever built a web application using the Google Maps API, you are likely intimately familiar with this line of code:



map.setCenter( new google.maps. LatLng( 37.4419, - 122. 1419),  13);


setCenterMapKit on the iPhone does not include a way to set the zoom level. Instead, the zoom level is set implicitly by defining the MKCoordinateRegionMKMapView explicitly. In this post, I’ll give you code you can drop into your own projects and start using immediately. My next post will detail exactly how it works.

The Code

MKMapView


// MKMapView+ZoomLevel.h

#import <MapKit/MapKit.h>

@interface

void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
    zoomLevel:(NSUInteger)zoomLevel
    animated:(BOOL)animated;

@end



// MKMapView+ZoomLevel.m 
   
 
#import "MKMapView+ZoomLevel.h"
#define MERCATOR_OFFSET 268435456
#define MERCATOR_RADIUS 85445659.44705395@implementation
#pragma mark -
#pragma mark Map conversion methodsdouble)longitudeToPixelSpaceX:(double)longitude
 {
     return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
 }double)latitudeToPixelSpaceY:(double)latitude
 {
     return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
 }double)pixelSpaceXToLongitude:(double)pixelX
 {
     return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
 }double)pixelSpaceYToLatitude:(double)pixelY
 {
     return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
 }#pragma mark -
#pragma mark Helper methodsMKCoordinateSpan)coordinateSpanWithMapView:(MKMapView *)mapView
     centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
     andZoomLevel:(NSUInteger)zoomLevel
 {
     // convert center coordiate to pixel space
     double centerPixelX = [self longitudeToPixelSpaceX:centerCoordinate.longitude];
     double centerPixelY = [self latitudeToPixelSpaceY:centerCoordinate.latitude];
     
     // determine the scale value from the zoom level
     NSInteger zoomExponent = 20 - zoomLevel;
     double zoomScale = pow(2, zoomExponent);
     
     // scale the map’s size in pixel space
     CGSize mapSizeInPixels = mapView.bounds.size;
     double scaledMapWidth = mapSizeInPixels.width * zoomScale;
     double scaledMapHeight = mapSizeInPixels.height * zoomScale;
     
     // figure out the position of the top-left pixel
     double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
     double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);
     
     // find delta between left and right longitudes
     CLLocationDegrees minLng = [self pixelSpaceXToLongitude:topLeftPixelX];
     CLLocationDegrees maxLng = [self pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
     CLLocationDegrees longitudeDelta = maxLng - minLng;
     
     // find delta between top and bottom latitudes
     CLLocationDegrees minLat = [self pixelSpaceYToLatitude:topLeftPixelY];
     CLLocationDegrees maxLat = [self pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
     CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
     
     // create and return the lat/lng span
     MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
     return span;
 }#pragma mark -
#pragma mark Public methodsvoid)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
     zoomLevel:(NSUInteger)zoomLevel
     animated:(BOOL)animated
 {
     // clamp large numbers to 28
     zoomLevel = MIN(zoomLevel, 28);
     
     // use the zoom level to compute the region
     MKCoordinateSpan span = [self coordinateSpanWithMapView:self centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
     MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
     
     // set the region like normal
     [self setRegion:region animated:animated];
 }@end


If you’re wondering why this works, check out my next post where I describe in gruesome detail the math behind the code.

how it works, just that it does

Test the Code

MKMapView


// ZoomLevelTestViewController.m 
   
 
#import "MKMapView+ZoomLevel.h"
#define GEORGIA_TECH_LATITUDE 33.777328
#define GEORGIA_TECH_LONGITUDE -84.397348#define ZOOM_LEVEL 14
void)viewDidAppear:(BOOL)animated
 {
     [super viewDidAppear:animated];
     
     CLLocationCoordinate2D centerCoord = { GEORGIA_TECH_LATITUDE, GEORGIA_TECH_LONGITUDE };
     [mapView setCenterCoordinate:centerCoord zoomLevel:ZOOM_LEVEL animated:NO];
 }



And, viola! Your map should zoom in to where you can see the Georgia Tech campus.

Results

To verify that the zoom level is set correctly, I wrote a simple web-based Google Maps application to make sure the web and native zoom levels matched. Both apps were centered at {33.777328, -84.397348} (Georgia Tech). In the images below, the iPhone on the left is running the native app and the iPhone on the right is running the web app:

iOS 缩放等级  Set the Zoom Level of an MKMapView_git

iOS 缩放等级  Set the Zoom Level of an MKMapView_#define_02

iOS 缩放等级  Set the Zoom Level of an MKMapView_#define_03

As you can see, they match.

That’s a Wrap

MKMapView+ZoomLevel

Next time, I’ll go over exactly why the code above works. But, for now, enjoy the freedom to set zoom levels!



Posted in iPhone DevelopmentTagged mapkitmaps


60 Responses to “Set the Zoom Level of an MKMapView”

1. RAVI KB 
     November 22, 2013 at 6:36 am  
     |  
     Permalink 
     
    
 Great job
 But from this how do I will get current zoom level of map view???2.   
    
John Gazzini 
     December 19, 2013 at 4:01 am  
     |  
     Permalink 
     
    
 Thanks; this saved me several minutes of my life. Like… at least 4 minutes. It looks like you posted this a few years ago, but wherever you are, I hope you’re wildly successful.
 // John3. Nordin B 
     March 13, 2014 at 1:49 pm  
     |  
     Permalink 
     
    
 Thanks a lot for this post my friend,
 I just started developing for iOS and I was surprised why there was no way set a zoomlevel. When a user zooms, it’s because the user wants to know the exact spot of the location and not the area.
 By the way, you’re post was very easy to follow (you should be a teacher some day).4. Kyle R 
     March 13, 2014 at 4:39 pm  
     |  
     Permalink 
     
    
 I too want to get the zoom level of a map.5. kups 
     May 10, 2014 at 6:01 am  
     |  
     Permalink 
     
    
 Thanks for the great tutorial. But When i used this class with 100′s of map points in same lat longs, the map points are over lapping each other and unable to click particular map point Please check this link i want to display using spiderfy leafleft animation.. SO by using spiderfy animation we can achive this http://www.yourmapper.com/demo/spiderfy.htm . any idea?6. Thai 
     May 16, 2015 at 4:50 am  
     |  
     Permalink 
     
    
 Your post was very helpful that can help me convert a zoom from Google map to a span on Apple map. Thanks a lot.
 Do you know how to get a zoom level if I have a span. I think I need to do the contrary but I not very good at math and those calculation are really complicated
 Thanks in advance7.   
    
Mike 
     June 9, 2015 at 3:28 am  
     |  
     Permalink 
     
    
 If anyone needs it I translated this to a Swit extension for use in a project I’m working on.
 I’ll be adding the inverse operation soon (need it for same project). Just working out some kinks in it now.
 Thanks Troy for this and thanks to Dave in the comments for the inverse function.
 https://github.com/goto10/EBCExtensions8. Ahmed ESS 
     June 14, 2015 at 12:07 pm  
     |  
     Permalink 
     
    
 For those who need to get zoom level, use that code :
 @interface MKMapView (ZoomLevelGetter)
 - (int)getZoomLevel;
 @end
 @implementation MKMapView (ZoomLevelGetter)
 - (int)getZoomLevel
 {
 CLLocationDegrees longitudeDelta = self.region.span.longitudeDelta;
 CGFloat mapWidthInPixels = self.bounds.size.width*2;//2 is for retina display
 double zoomScale = longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * mapWidthInPixels);
 double zoomer = MAX_GOOGLE_LEVELS – log2( zoomScale );
 if ( zoomer < 0 ) zoomer = 0;
 zoomer = round(zoomer);
 return (int)zoomer;
 }
 @end9. Mike Lanza 
     September 29, 2015 at 9:03 pm  
     |  
     Permalink 
     
    
 Thanks to Mike for the Swift Extension! I do need the inverse function, so I hope you get around to posting it.10.   
    
ヘアアクセ 
     November 27, 2015 at 6:57 am  
     |  
     Permalink

  1. プロムドレスのアクセサリーの多くには、これまでに中立的なヒョウ?プリントを混合することを見つけるのは喜ぶかもしれません。それを変形できるので決してかつらを折ってください。金属閉鎖なしでポニーテールホルダーを使用してここでは、あなたは男性の髪のためのいくつかのヘアケアのヒントを与えます。暗い色が全体的な体はあなたの顔のモデルにするのを助けるかもしれない内に支払う思考の素晴らしい方法です。この製品の高度な技術とその顕著な特徴の一つは、小さな板を使用しています。父のカレン?メドレー株に、マイケルコースのハンドバッグ
    ヘアアクセ http://ljvbw.ditib.de/cli/PYY/dhCb



标签:Set,Level,double,self,缩放,zoom,zoomLevel,MERCATOR,level
From: https://blog.51cto.com/u_16124099/6326804

相关文章

  • VTK 视角的旋转、平移、缩放
    在CAD/CAM软件中,都需要旋转、平移和缩放视角,来观察操作图形。由于VTK定义的交互的类型不是很适用,所有通过定义一套自己的交互方式。在下面代码中,鼠标左键平移,滚轮缩放,右键旋转。先定义一个交互类型。继承自vtkInteractorStyleTrackballCamera,并且交换按键。classNormal3DCame......
  • Failed to execute 'setSelectionRange' on 'HTMLInputElement'
    jcubic commented on7Jan2016WhenIusenumberinputI'vegoterrorinGoogleChromeUncaughtInvalidStateError:Failedtoexecute'setSelectionRange'on'HTMLInputElement':Theinputelement'stype('number')......
  • Java入门9(HashSet,File文件类)
    HashSetjdk1.7之前,使用数组加链表的方式实现jdk1.8之后,在链表长度大于8并且数组长度超过32的情况下,会转成红黑树结构HashSet的本质是一个HashMap,它所有的value都是一致的,传入的参数作为key,因此HashSet中不允许重复数据存储的时候,键值对位于的数组位置,之和key的HashCode值有关......
  • APP启动异常崩溃--pointer being freed was not allocated *** set a breakpoint in m
    一、问题场景APP启动异常崩溃BlockChainStep(1332,0x7000057ad000)malloc:*errorforobject0x600000008300:pointerbeingfreedwasnotallocated*setabreakpointinmalloc_error_breaktodebug二、崩溃原因在Xcode8中,如果你的图片资源文件里有16位图或者图片显示模......
  • set character_set_database=utf8;set character_set_server=utf8;
    D:\mysql-5.6.24-win32\bin\mysql-urootWelcometotheMySQLmonitor.Commandsendwith;or\g.YourMySQLconnectionidis55Serverversion:5.6.24MySQLCommunityServer(GPL)Copyright(c)2000,2015,Oracleand/oritsaffiliates.......
  • [atARC156F]Make Same Set
    考虑网络流,具体建图如下:整张图共\(4\)层,用\((i,j)\)表示第\(i\)层的第\(j\)个点,则边集包含从\(S\)向\((1,i)\)连流量为\(1\)的边从\((1,i)\)向\((2,a_{i})\)和\((2,b_{i})\)连流量为\(1\)的边从\((2,i)\)向\((3,i)\)连流量为\(1\)的边从\((3,a_{i})\)和\((3,c_{i})\)向\((4,......
  • 踩坑:nacos启动报错提示需要设置JDK环境 ,报错:ERROR: Please set the JAVA_HOME variabl
    换了个Windows11的新电脑,因为个人工作、学习需要,就重新下载了Nacos并解压使用,结果就踩了个坑,使用下面命令启动Nacos服务端时:startup.cmd-mstandalone直接在黑窗口提示:ERROR:PleasesettheJAVA_HOMEvariableinyourenvironment,Weneedjava(x64)!jdk8orlaterisbet......
  • 史上最全的WebSettings说明
    setAllowContentAccess(booleanallow) 是否允许在WebView中访问内容URL(ContentUrl),默认允许。内容Url访问允许WebView从安装在系统中的内容提供者载入内容。setAllowFileAccess(booleanallow) 是否允许访问文件,默认允许。注意,这里只是允许或禁止对文件系统的访问,Assets和re......
  • Vue进阶(九十八):Vue.set() 和 this.$set()
    (文章目录)一、应用场景有时候我们会看到如下代码:在我们使用vue进行开发的过程中,可能会遇到这样一种情况:当创建vue实例后,再次给对象赋值时,发现数据并不会自动更新到视图上去;当我们去阅读vue文档的时候,会发现有这么一句话:如果在实例创建之后添加新的属性到实例上,它不会触发视图......
  • Set集合
    set集合一直以来,JS只能使用数组和对象来保存多个数据,缺乏像其他语言那样拥有丰富的集合类型。因此,ES6新增了两种集合类型(set和map),用于在不同的场景中发挥作用。set用于存放不重复的数据如何创建set集合newSet();//创建一个没有任何内容的set集合newSet(iterable);......