Weex開發之地圖篇

在移動應用開發中,地圖是一個很重要的工具,基於地圖的定位、導航等特色衍生出了不少著名的移動應用。在Weex開發中,若是要使用定位、導航和座標計算等常見的地圖功能,可使用weex-amap插件。html

weex-amap是高德針對Weex開發的一款地圖插件,在Eros開發中,Eros對weex-amap進行二次封裝,以便讓開發者更集成地圖功能。和其餘的插件同樣,集成此插件須要在原平生臺中進行集成。vue

本文介紹的是如何在iOS中集成weex-amap,以及它的一些核心功能。本文將要介紹的內容以下:html5

1.高德地圖開發準備工做android

    • 1.1 iOS高德地圖開發流程簡單介紹
    • 1.2 android高德地圖開發流程簡單介紹
    • 1.3 web高德地圖開發流程簡單介紹

    2. weex-iOS地圖組件擴展方式介紹ios

    • 2.1 dwd-weex-amap
    • 2.2 dwd-weex-amap-marker
    • 2.3 dwd-weex-amap-info-window
    • 2.4 dwd-weex-amap-circle
    • 2.5 dwd-weex-amap-polygon
    • 2.5 dwd-weex-amap-polyline

    3.weex-android地圖組件擴展方式介紹git

    • 3.1 dwd-weex-amap
    • 3.2 dwd-weex-amap-marker
    • 3.3 dwd-weex-amap-info-window
    • 3.4 dwd-weex-amap-circle
    • 3.5 dwd-weex-amap-polygon
    • 3.6 dwd-weex-amap-polyline

    4.weex-html5地圖組件擴展方式介紹github

    • 4.1 dwd-weex-amap
    • 4.2 dwd-weex-amap-marker
    • 4.3 dwd-weex-amap-info-window
    • 4.4 dwd-weex-amap-circle
    • 4.5 dwd-weex-amap-polygon
    • 4.6 dwd-weex-amap-polyline

    5.獲取地圖數據(例如騎行路徑規劃)web

    • 5.1 weex-iOS地圖騎行路徑規劃
    • 5.2 weex-android地圖騎行路徑規劃
    • 5.3 weex-web地圖騎行路徑規劃

    在這裏插入圖片描述

    準備工做

    1.1 開發流程簡紹

    1.使用 CocoaPods 安裝AMapSearch,AMap3DMap SDK
    2.前往高德開放平臺控制檯申請 iOS Key
    3.配置高德Key至AppDelegate.m文件windows

    1.2 android高德地圖開發流程簡紹

    1.使用 CocoaPods 安裝AMapSearch,AMap3DMap SDK
    2.前往高德開放平臺控制檯申請 android Key
    3.AndroidManifest.xml的application標籤中配置Key
    4.AndroidManifest.xml中配置權限api

    1.3 HTML5高德地圖開發流程簡紹

    1.前往高德開放平臺控制檯申請 jsAPI Key
    2.可經過CDN同步加載方式或使用require異步方式來加載key

    參考:高德地圖開發文檔vue-amap開發文檔

    weex-iOS地圖組件擴展

    2.1 weex-amap

    地圖展現是地圖最基本的功能,其常見的效果以下:
    在這裏插入圖片描述

    若有要在iOS中自定義weex-amap能夠從如下幾個步驟完成:

    1.新建DMapViewComponent類繼承WXComponent;

    2.在DMapViewComponent實現文件中實現MAMapViewDelegate代理; 
       3. 重寫DMapViewComponent的loadView方法加載地圖視圖並設置自身爲代理對象; 
       4.在DMapViewComponent的初始化函數viewDidLoad中作一些準備工做;  
       5.在DMapViewComponent的initWithRef方法中實現屬性綁定;  
       6.經過fireEvent添加適當時機能夠觸發的事件;  
       7.重寫insertSubview方法來添加子組建包括覆蓋物,線,圓等等。

    下面是部分的業務實現代碼:

    @implementation DMapViewComponent
    ...
    // 屬性綁定
    - (instancetype)initWithRef:(NSString *)ref
                           type:(NSString*)type
                         styles:(nullable NSDictionary *)styles
                     attributes:(nullable NSDictionary *)attributes
                         events:(nullable NSArray *)events
                   weexInstance:(WXSDKInstance *)weexInstance
    {
        self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
        if (self) {
            // 中心點
            NSArray *center = [attributes map_safeObjectForKey:@"center"];
            _zoomLevel = [[attributes map_safeObjectForKey:@"zoom"] floatValue];
            // 是否容許顯示指南針
            _compass = [[attributes map_safeObjectForKey:@"compass"] boolValue];
            // sdkKey
            if ([attributes map_safeObjectForKey:@"sdkKey"]) {
                [self setAPIKey:[attributes[@"sdkKey"] objectForKey:@"ios"] ? : @""];
            }
    ...
        }
        return self;
    }
    // 重寫DMapViewComponent的loadView方法加載地圖視圖並設置自身爲代理對象   
    - (UIView *) loadView
    {
        UIWindow *window = [UIApplication sharedApplication].keyWindow;
        CGSize windowSize = window.rootViewController.view.frame.size;
        self.mapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, 0, windowSize.width, windowSize.height)];
        self.mapView.showsUserLocation = _showGeolocation;
        self.mapView.delegate = self;
        self.mapView.customMapStyleEnabled = YES;
        [self.mapView setCustomMapStyleWithWebData:[self getMapData]];
    
        return self.mapView;
    }
    // 設置地圖樣式
    - (NSData *)getMapData
    {
        NSString *path = [NSString stringWithFormat:@"%@/gaodeMapStyle.data", [NSBundle mainBundle].bundlePath];
        NSData *data = [NSData dataWithContentsOfFile:path];
        return data;
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        self.mapView.showsScale = _showScale;
        self.mapView.showsCompass = _compass;
        [self.mapView setCenterCoordinate:_centerCoordinate];
        [self.mapView setZoomLevel:_zoomLevel];
    }
    
    // 添加覆蓋物
    - (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
    {
        if ([subcomponent isKindOfClass:[DMapRenderer class]]) {
            DMapRenderer *overlayRenderer = (DMapRenderer *)subcomponent;
            [self addOverlay:overlayRenderer];
        }else if ([subcomponent isKindOfClass:[DMapViewMarkerComponent class]]) {
            [self addMarker:(DMapViewMarkerComponent *)subcomponent];
        }
    }
    // 更新屬性
    - (void)updateAttributes:(NSDictionary *)attributes
    {
    ...
        if (attributes[@"zoom"]) {
            [self setZoomLevel:[attributes[@"zoom"] floatValue]];
        }
     ...
    }
    #pragma mark - component interface
    - (void)setAPIKey:(NSString *)appKey
    {
        [AMapServices sharedServices].apiKey = appKey;
    }
    - (void)setZoomLevel:(CGFloat)zoom
    {
        [self.mapView setZoomLevel:zoom animated:YES];
    }
    #pragma mark - publish method
    - (NSDictionary *)getUserLocation
    {
        if(self.mapView.userLocation.updating && self.mapView.userLocation.location) {
            NSArray *coordinate = @[[NSNumber numberWithDouble:self.mapView.userLocation.location.coordinate.longitude],[NSNumber numberWithDouble:self.mapView.userLocation.location.coordinate.latitude]];
            NSDictionary *userDic = @{@"result":@"success",@"data":@{@"position":coordinate,@"title":@""}};
            return userDic;
        }
        return @{@"resuldt":@"false",@"data":@""};
    }
    
    #pragma mark - mapview delegate
    /*!
     @brief 根據anntation生成對應的View
     */
    - (MAAnnotationView*)mapView:(MAMapView *)mapView viewForAnnotation:(id <MAAnnotation>)annotation
    {
        if ([annotation isKindOfClass:[MAPointAnnotation class]])
        {
            MAPointAnnotation *pointAnnotation = (MAPointAnnotation *)annotation;
            if ([pointAnnotation.component isKindOfClass:[WXMapInfoWindowComponent class]]) {
                return [self _generateCustomInfoWindow:mapView viewForAnnotation:pointAnnotation];
    
            }else {
                return [self _generateAnnotationView:mapView viewForAnnotation:pointAnnotation];
            }
        }
    
        return nil;
    }
    
    /**
     * @brief 當選中一個annotation views時,調用此接口
     * @param mapView 地圖View
     * @param view 選中的annotation views
     */
    - (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view
    {
        MAPointAnnotation *annotation = view.annotation;
        for (WXComponent *component in self.subcomponents) {
            if ([component isKindOfClass:[WXMapViewMarkerComponent class]] &&
                [component.ref isEqualToString:annotation.component.ref]) {
                WXMapViewMarkerComponent *marker = (WXMapViewMarkerComponent *)component;
                if (marker.clickEvent) {
                    [marker fireEvent:marker.clickEvent params:[NSDictionary dictionary]];
                }
            }
        }
    }
    
    /**
     * @brief 當取消選中一個annotation views時,調用此接口
     * @param mapView 地圖View
     * @param view 取消選中的annotation views
     */
    - (void)mapView:(MAMapView *)mapView didDeselectAnnotationView:(MAAnnotationView *)view
    {
    
    }
    
    /**
     * @brief 地圖移動結束後調用此接口
     * @param mapView       地圖view
     * @param wasUserAction 標識是不是用戶動做
     */
    - (void)mapView:(MAMapView *)mapView mapDidMoveByUser:(BOOL)wasUserAction
    {
        if (_isDragend) {
            [self fireEvent:@"dragend" params:[NSDictionary dictionary]];
        }
    }
    
    /**設置地圖縮放級別 */
    - (void)setMapViewRegion:(NSMutableArray *)poiArray animated:(BOOL)animated {
        NSMutableArray *arrays = [NSMutableArray array];
        for (MAPointAnnotation *anot in self.mapView.annotations) {
            CLLocationCoordinate2D coordinate = anot.coordinate;
            NSDictionary *poidic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:coordinate.latitude * 1000000], @"lat",
                                    [NSNumber numberWithInt:coordinate.longitude * 1000000], @"lng", nil];
            [arrays addObject:poidic];
        }
    
        MACoordinateRegion region = [self getCoordinateMapSpan:arrays];
        [self.mapView setRegion:region animated:animated];
    }
    
    /**配置地圖region */
    - (MACoordinateRegion)getCoordinateMapSpan:(NSMutableArray *)knightArray {
        MACoordinateRegion region;
        MACoordinateSpan span;
    
        CLLocationDegrees maxLat = -90;
        CLLocationDegrees maxLon = -180;
        CLLocationDegrees minLat = 90;
        CLLocationDegrees minLon = 180;
    
        if (knightArray && knightArray.count > 1) {
            for (int i = 0; i < knightArray.count; i++) {
                NSDictionary *knightDictionary = [knightArray objectAtIndex:i];
                float lat = [[knightDictionary objectForKey:@"lat"] floatValue] / 1000000;
                float lng = [[knightDictionary objectForKey:@"lng"] floatValue] / 1000000;
    
                if(lat > maxLat)
                    maxLat = lat;
                if(lat < minLat)
                    minLat = lat;
                if(lng > maxLon)
                    maxLon = lng;
                if(lng < minLon)
                    minLon = lng;
            }
    
            span.latitudeDelta = (maxLat - minLat) * 2 + 0.005;
            span.longitudeDelta = (maxLon - minLon) * 2 + 0.005;
            region.center.latitude = (maxLat + minLat) / 2;
            region.center.longitude = (maxLon + minLon) / 2;
            region.span = span;
        } else {
            NSDictionary *knightDictionary = [knightArray objectAtIndex:0];
            span.latitudeDelta = 0.01;
            span.longitudeDelta = 0.01;
            float lat = [[knightDictionary objectForKey:@"lat"] floatValue] / 1000000;
            float lng = [[knightDictionary objectForKey:@"lng"] floatValue] / 1000000;
            if (lat !=0 && lng != 0) {
                region.center.longitude = lng;
                region.center.latitude = lat;
            } else {
                region.center = [[ShopLocateManager shared] getLocationCoordinate];
            }
            region.span = span;
        }
    
        return region;
    }
    ...
    @end

    2.2 weex-amap-marker

    marker主要用於實現錨點,其效果以下:
    在這裏插入圖片描述

    要在Weex中自定義錨點,須要遵循如下幾步:

    1. 新建DMapViewMarkerComponent類繼承WXComponent;
    2. 在DMapViewComponent中使用mapview的addAnnotation方法添加DMapViewMarkerComponent組件;
    3. 在DMapViewComponent重寫insertSubview方法來添加子組建覆蓋物。

    部分實現代碼以下:

    - (instancetype)initWithRef:(NSString *)ref
                           type:(NSString*)type
                         styles:(nullable NSDictionary *)styles
                     attributes:(nullable NSDictionary *)attributes
                         events:(nullable NSArray *)events
                   weexInstance:(WXSDKInstance *)weexInstance
    {
        self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
        if (self) {
            if ([events containsObject:@"click"]) {
                _clickEvent = @"click";
            }
            NSArray *offset = attributes[@"offset"];
            if ([WXConvert isValidatedArray:offset]) {
                _offset = CGPointMake([WXConvert CGFloat:offset[0]],
                                      [WXConvert CGFloat:offset[1]]);//[WXConvert sizeToWXPixelType:attributes[@"offset"] withInstance:self.weexInstance];
            }
            if (styles[@"zIndex"]) {
                _zIndex = [styles[@"zIndex"] integerValue];
            }
            _hideCallout = [[attributes map_safeObjectForKey:@"hideCallout"] boolValue];
            NSArray *position = [attributes map_safeObjectForKey:@"position"];
            if ([WXConvert isValidatedArray:position]) {
                _location = [attributes map_safeObjectForKey:@"position"];
            }
            _title = [attributes map_safeObjectForKey:@"title"];
            _icon = [attributes map_safeObjectForKey:@"icon"];
        }
        return self;
    }
    
    - (void)updateAttributes:(NSDictionary *)attributes
    {
        DMapViewComponent *mapComponent = (DMapViewComponent *)self.supercomponent;
        if (attributes[@"title"]) {
            _title = attributes[@"title"];
            [mapComponent updateTitleMarker:self];
        }
    
        if ([attributes map_safeObjectForKey:@"icon"]) {
            _icon = attributes[@"icon"];
            [mapComponent updateIconMarker:self];
        }
    
        NSArray *position = [attributes map_safeObjectForKey:@"position"];
        if ([WXConvert isValidatedArray:position]) {
            _location = position;
            [mapComponent updateLocationMarker:self];
        }
    }

    weex-amap-info-window

    weex-amap-info-window組件主要用於顯示地圖信息,如地圖的圖片模式,其效果以下:
    在這裏插入圖片描述

    要自定義窗體組件,須要用到如下幾個步驟:

    1. 新建DMapInfoWindowComponent類繼承WXComponent;
    2. 在DMapViewComponent中使用mapview的addAnnotation方法添加DMapInfoWindowComponent組件;
    3. 在DMapViewComponent重寫insertSubview方法來添加子組建信息窗體。

    部分實現代碼以下:

    - (instancetype)initWithRef:(NSString *)ref
                           type:(NSString*)type
                         styles:(nullable NSDictionary *)styles
                     attributes:(nullable NSDictionary *)attributes
                         events:(nullable NSArray *)events
                   weexInstance:(WXSDKInstance *)weexInstance
    {
        self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
        if (self) {
            if (attributes[@"open"]) {
                _isOpen = [attributes[@"open"] boolValue];
            }
    
        }
        return self;
    }
    
    - (UIView *) loadView
    {
        return [[DMapInfoWindow alloc] initWithAnnotation:_annotation reuseIdentifier:_identifier];
    }
    
    - (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index{}
    - (void)updateAttributes:(NSDictionary *)attributes
    {
        [super updateAttributes:attributes];
        if (attributes[@"open"])
        {
            _isOpen = [attributes[@"open"] boolValue];
            if (_isOpen) {
                [self _addSubView];
            }else {
                [self _removeViewFromSuperView];
            }
        }
    }
    
    #pragma mark - private method
     1. (void)_addSubView
    {
        [self _removeViewFromSuperView];
        [(DMapViewComponent *)self.supercomponent addMarker:self];
    }
    
     2. (void)_removeViewFromSuperView
    {
        [(DMapViewComponent *)self.supercomponent removeMarker:self];
    }

    2.4 weex-amap-circle

    weex-amap-circle組件主要用於實現畫圈功能,如地圖範圍,其效果以下圖所示:
    在這裏插入圖片描述

    1. 新建DMapCircleComponent類繼承WXComponent;

      1. 在DMapViewComponent中使用mapview的addOverlay方法添加DMapCircleComponent組件;
    2. 在DMapViewComponent重寫insertSubview方法來添加子組建圓。

    下面是部分實現邏輯:

    - (instancetype)initWithRef:(NSString *)ref
                           type:(NSString*)type
                         styles:(nullable NSDictionary *)styles
                     attributes:(nullable NSDictionary *)attributes
                         events:(nullable NSArray *)events
                   weexInstance:(WXSDKInstance *)weexInstance
    {
        self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
        if (self) {
            NSArray *centerArray = [attributes map_safeObjectForKey:@"center"];
            if ([WXConvert isValidatedArray:centerArray]) {
                _center = centerArray;
            }
            _radius = [[attributes map_safeObjectForKey:@"radius"] doubleValue];
        }
        return self;
    }
    
    - (void)updateAttributes:(NSDictionary *)attributes
    {
        NSArray *centerArray = [attributes map_safeObjectForKey:@"center"];
        DMapViewComponent *parentComponent = (DMapViewComponent *)self.supercomponent;
        if ([WXConvert isValidatedArray:centerArray]) {
            _center = centerArray;
            [parentComponent removeOverlay:self];
            [parentComponent addOverlay:self];
        }else if ([[attributes map_safeObjectForKey:@"radius"] doubleValue] >= 0) {
            _radius = [[attributes map_safeObjectForKey:@"radius"] doubleValue];
            [parentComponent removeOverlay:self];
            [parentComponent addOverlay:self];
        }else {
            [super updateAttributes:attributes];
        }
    }

    2.5 weex-amap-polygon

    weex-amap-polygon主要用於繪製多邊形,其效果以下圖:
    在這裏插入圖片描述

    要自定義weex-amap-polygon,能夠從如下步驟着手:

    1. 新建DMapPolygonComponent類繼承WXComponent;
    2. 在DMapViewComponent中使用mapview的addOverlay方法添加DMapPolygonComponent組件;
    3. 在DMapViewComponent重寫insertSubview方法來添加子組建多邊形。

    部分實現代碼以下:

    - (instancetype)initWithRef:(NSString *)ref
                           type:(NSString*)type
                         styles:(nullable NSDictionary *)styles
                     attributes:(nullable NSDictionary *)attributes
                         events:(nullable NSArray *)events
                   weexInstance:(WXSDKInstance *)weexInstance
    {
        self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
        if (self) {
            _fillColor = [attributes map_safeObjectForKey:@"fillColor"];
            _fillOpacity = [attributes map_safeObjectForKey:@"fillOpacity"];
        }
        return self;
    }
    
    - (void)updateAttributes:(NSDictionary *)attributes
    {
        if ([attributes map_safeObjectForKey:@"fillColor"]) {
            _fillColor = [attributes map_safeObjectForKey:@"fillColor"];
        }else if ([attributes map_safeObjectForKey:@"fillOpacity"]) {
            _fillOpacity = [attributes map_safeObjectForKey:@"fillOpacity"];
        }else {
            [super updateAttributes:attributes];
        }
    }

    2.6 weex-amap-polyline

    weex-amap-polyline組件主要用於在地圖上實現劃線操做,其最終效果以下圖:
    在這裏插入圖片描述

    在iOS中,自定義直接須要從如下幾步着手:

    1. 新建DMapPolylineComponent類繼承WXComponent;
    2. 在DMapViewComponent中使用mapview的addOverlay方法添加DMapPolylineComponent組件;
    3. 在DMapViewComponent重寫insertSubview方法來添加子組建折線。
    @implementation DMapPolylineComponent
    
    
    - (instancetype)initWithRef:(NSString *)ref
                           type:(NSString*)type
                         styles:(nullable NSDictionary *)styles
                     attributes:(nullable NSDictionary *)attributes
                         events:(nullable NSArray *)events
                   weexInstance:(WXSDKInstance *)weexInstance
    {
        self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
        if (self) {
            NSArray * pathArray = [attributes map_safeObjectForKey:@"path"];
            if ([WXConvert isValidatedArray:pathArray]) {
                _path = pathArray;
            }
            _strokeColor = [attributes map_safeObjectForKey:@"strokeColor"];
            _strokeWidth = [[attributes map_safeObjectForKey:@"strokeWidth"] doubleValue];
            _strokeOpacity = [[attributes map_safeObjectForKey:@"strokeOpacity"] doubleValue];
            _strokeStyle = [attributes map_safeObjectForKey:@"strokeStyle"];
        }
        _viewLoaded = NO;
        return self;
    }
    
    - (void)updateAttributes:(NSDictionary *)attributes
    {
        NSArray * pathArray = [attributes map_safeObjectForKey:@"path"];
        DMapViewComponent *parentComponent = (DMapViewComponent *)self.supercomponent;
        if (pathArray) {
            if ([WXConvert isValidatedArray:pathArray]) {
                _path = pathArray;
            }
            [parentComponent removeOverlay:self];
            [parentComponent addOverlay:self];
            return;
        }else if ([attributes map_safeObjectForKey:@"strokeColor"]) {
            _strokeColor = [attributes map_safeObjectForKey:@"strokeColor"];
        }else if ([[attributes map_safeObjectForKey:@"strokeWidth"] doubleValue] >= 0) {
            _strokeWidth = [[attributes map_safeObjectForKey:@"strokeWidth"] doubleValue];
        }else if ([[attributes map_safeObjectForKey:@"strokeOpacity"] doubleValue] >= 0) {
            _strokeOpacity = [[attributes map_safeObjectForKey:@"strokeOpacity"] doubleValue];
        }else if ([attributes map_safeObjectForKey:@"strokeStyle"]) {
            _strokeStyle = [attributes map_safeObjectForKey:@"strokeStyle"];
        }
        [parentComponent updateOverlayAttributes:self];
    }
    
    @end

    地圖組件擴展

    固然,咱們也能夠不使用weex-amap,而是直接使用高德地圖進行擴展。

    3.1 weex-amap

    例如,咱們本身擴展一個基於原生高德SDK生成的weex-amap組件。
    在這裏插入圖片描述
    要實現這麼一個地圖顯示的功能,實現的步驟以下:

    1. 新建DMapViewComponent類繼承WXVContainer實現LocationSource;
    2. 使用initComponentHostView(context)初始化;
    3. 在DMapViewComponent實現文件中實現初始化map對象initMap,設置map的key;
    4. @WXComponentProp註解實現屬性綁定;
    5. 經過fireEvent添加適當時機能夠觸發的事件;
    6. 設置mapview的setInfoWindowAdapter,addPolyline,addPolygon,addCircle,addMarker等方式來實現覆蓋物,,線,圓等等。

    實現代碼能夠參考下面的代碼:

    @Override
        protected FrameLayout initComponentHostView(@NonNull Context context) {
            mapContainer = new FrameLayout(context) {
                @Override
                public boolean onInterceptTouchEvent(MotionEvent ev) {
                    // 解決與Scroller的滑動衝突
                    if (ev.getAction() == MotionEvent.ACTION_UP) {
                        requestDisallowInterceptTouchEvent(false);
                    } else {
                        requestDisallowInterceptTouchEvent(true);
                    }
                    return false;
                }
            };
            mapContainer.setBackgroundColor(fakeBackgroundColor);
            if (context instanceof Activity) {
                mActivity = (Activity) context;
            }
    
            return mapContainer;
        }
    
        @Override
        protected void setHostLayoutParams(FrameLayout host, int width, int height, int left, int right, int top, int bottom) {
            super.setHostLayoutParams(host, width, height, left, right, top, bottom);
            if (!isMapLoaded.get() && !isInited.get()) {
                isInited.set(true);
                mapContainer.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mMapView = new TextureMapView(getContext());
                        mapContainer.addView(mMapView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                ViewGroup.LayoutParams.MATCH_PARENT));
                        WXLogUtils.e(TAG, "Create MapView " + mMapView.toString());
                        initMap();
                    }
                }, 0);
            }
        }
    
        private void initMap() {
            mMapView.onCreate(null);
            isMapLoaded.set(false);
            if (mAMap == null) {
                mAMap = mMapView.getMap();
    
                mAMap.setInfoWindowAdapter(new InfoWindowAdapter(this));
                mAMap.setOnMapLoadedListener(new AMap.OnMapLoadedListener() {
                    @Override
                    public void onMapLoaded() {
                        WXLogUtils.e(TAG, "Map loaded");
                        isMapLoaded.set(true);
                        mZoomLevel = mAMap.getCameraPosition().zoom;
                        mMapView.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                execPaddingTasks();
                            }
                        }, 16);
                    }
                });
    
                // 綁定 Marker 被點擊事件
                mAMap.setOnMarkerClickListener(new AMap.OnMarkerClickListener() {
                    // marker 對象被點擊時回調的接口
                    // 返回 true 則表示接口已響應事件,不然返回false
                    @Override
                    public boolean onMarkerClick(Marker marker) {
    
                        if (marker != null) {
                            for (int i = 0; i < getChildCount(); i++) {
                                if (getChild(i) instanceof DMapMarkerComponent) {
                                    DMapMarkerComponent child = (DMapMarkerComponent) getChild(i);
                                    if (child.getMarker() != null && child.getMarker().getId() == marker.getId()) {
                                        child.onClick();
                                    }
                                }
                            }
                        }
                        return false;
                    }
                });
                mAMap.setOnCameraChangeListener(new AMap.OnCameraChangeListener() {
    
                    private boolean mZoomChanged;
    
                    @Override
                    public void onCameraChange(CameraPosition cameraPosition) {
                        mZoomChanged = mZoomLevel != cameraPosition.zoom;
                        mZoomLevel = cameraPosition.zoom;
                    }
    
                    @Override
                    public void onCameraChangeFinish(CameraPosition cameraPosition) {
                        if (mZoomChanged) {
    
                            float scale = mAMap.getScalePerPixel();
                            float scaleInWeex = scale / WXViewUtils.getWeexPxByReal(scale);
    
                            VisibleRegion visibleRegion = mAMap.getProjection().getVisibleRegion();
                            WXLogUtils.d(TAG, "Visible region: " + visibleRegion.toString());
                            Map<String, Object> region = new HashMap<>();
                            region.put("northeast", convertLatLng(visibleRegion.latLngBounds.northeast));
                            region.put("southwest", convertLatLng(visibleRegion.latLngBounds.southwest));
    
                            Map<String, Object> data = new HashMap<>();
                            data.put("targetCoordinate", cameraPosition.target.toString());
                            data.put("zoom", cameraPosition.zoom);
                            data.put("tilt", cameraPosition.tilt);
                            data.put("bearing", cameraPosition.bearing);
                            data.put("isAbroad", cameraPosition.isAbroad);
                            data.put("scalePerPixel", scaleInWeex);
                            data.put("visibleRegion", region);
                            getInstance().fireEvent(getRef(), WeexConstant.EVENT.ZOOM_CHANGE, data);
                        }
                    }
                });
    
                mAMap.setOnMapTouchListener(new AMap.OnMapTouchListener() {
                    boolean dragged = false;
    
                    @Override
                    public void onTouch(MotionEvent motionEvent) {
    
                        switch (motionEvent.getAction()) {
                            case MotionEvent.ACTION_MOVE:
                                dragged = true;
                                break;
                            case MotionEvent.ACTION_UP:
                                if (dragged)
                                    getInstance().fireEvent(getRef(), WeexConstant.EVENT.DRAG_CHANGE);
                                dragged = false;
                                break;
                        }
                    }
                });
                setUpMap();
            }
        }
    }

    3.2 weex-amap-info-window

    固然,咱們也可使用它實現weex-amap-info-window功能,雖然weex-amap-info-window已經被內置到weex-amap中。是的的思路以下:

    1. 新建DMapViewMarkerComponent類繼承WXComponent;
    2. 在DMapViewComponent中使用mapview的addMarker方法添加DMapViewMarkerComponent組件 。 在DMapViewComponent中使用mapview的addMarker方法添加DMapViewMarkerComponent組件 。
    private static class InfoWindowAdapter implements AMap.InfoWindowAdapter {
    
            private DMapViewComponent mWXMapViewComponent;
    
            InfoWindowAdapter(DMapViewComponent wxMapViewComponent) {
                mWXMapViewComponent = wxMapViewComponent;
            }
    
            @Override
            public View getInfoWindow(Marker marker) {
                return render(marker);
            }
    
            @Override
            public View getInfoContents(Marker marker) {
                return null;
    //            return render(marker);
            }
    
            private View render(Marker marker) {
                WXMapInfoWindowComponent wxMapInfoWindowComponent = mWXMapViewComponent.mInfoWindowHashMap.get(marker.getId());
                if (wxMapInfoWindowComponent != null) {
                    WXFrameLayout host = wxMapInfoWindowComponent.getHostView();
    //                WXFrameLayout content = (WXFrameLayout) host.getChildAt(0);
                    host.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
                    host.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
                    WXLogUtils.d(TAG, "Info size: " + host.getMeasuredWidth() + ", " + host.getMeasuredHeight());
                    return host;
                } else {
                    WXLogUtils.e(TAG, "WXMapInfoWindowComponent with marker id " + marker.getId() + " not found");
                }
                return null;
            }
        }

    html5地圖組件擴展

    固然,咱們可使用對html5的amap進行擴展,例如擴展weex-amap。

    4.1 weex-amap

    在這裏插入圖片描述
    示例代碼以下:

    <template>  
        <div class="amap-page-container">
          <el-amap ref="map" vid="amapDemo" :amap-manager="amapManager" :center="center" :zoom="zoom" :plugin="plugin" :events="events" class="amap-demo">
          </el-amap>
    
          <div class="toolbar">
            <button @click="getMap()">get map</button>
          </div>
        </div>
      </template>
    
      <style>
        .amap-demo {
          height: 300px;
        }
      </style>
    
      <script>
        // NPM 方式
        // import { AMapManager } from 'vue-amap';
        // CDN 方式
        let amapManager = new VueAMap.AMapManager();
        module.exports = {
          data: function() {
            return {
              amapManager,
              zoom: 12,
              center: [121.59996, 31.197646],
              events: {
                init: (o) => {
                  console.log(o.getCenter())
                  console.log(this.$refs.map.$$getInstance())
                  o.getCity(result => {
                    console.log(result)
                  })
                },
                'moveend': () => {
                },
                'zoomchange': () => {
                },
                'click': (e) => {
                  alert('map clicked');
                }
              },
              plugin: ['ToolBar', {
                pName: 'MapType',
                defaultType: 0,
                events: {
                  init(o) {
                    console.log(o);
                  }
                }
              }]
            };
          },
    
          methods: {
            getMap() {
              // amap vue component
              console.log(amapManager._componentMap);
              // gaode map instance
              console.log(amapManager._map);
            }
          }
        };
    </script>

    4.2 weex-amap-marker

    在這裏插入圖片描述
    實現代碼以下:

    <template>  
        <div class="amap-page-container">
          <el-amap vid="amapDemo" :zoom="zoom" :center="center" class="amap-demo">
            <el-amap-marker vid="component-marker" :position="componentMarker.position" :content-render="componentMarker.contentRender" ></el-amap-marker>
            <el-amap-marker v-for="(marker, index) in markers" :position="marker.position" :events="marker.events" :visible="marker.visible" :draggable="marker.draggable" :vid="index"></el-amap-marker>
          </el-amap>
          <div class="toolbar">
            <button type="button" name="button" v-on:click="toggleVisible">toggle first marker</button>
            <button type="button" name="button" v-on:click="changePosition">change position</button>
            <button type="button" name="button" v-on:click="chnageDraggle">change draggle</button>
            <button type="button" name="button" v-on:click="addMarker">add marker</button>
            <button type="button" name="button" v-on:click="removeMarker">remove marker</button>
          </div>
        </div>
      </template>
    
      <style>
        .amap-demo {
          height: 300px;
        }
      </style>
    
      <script>
        const exampleComponents = {
          props: ['text'],
          template: `<div>text from  parent: {{text}}</div>`
        }
        module.exports = {
          name: 'amap-page',
          data() {
            return {
              count: 1,
              slotStyle: {
                padding: '2px 8px',
                background: '#eee',
                color: '#333',
                border: '1px solid #aaa'
              },
              zoom: 14,
              center: [121.5273285, 31.21515044],
              markers: [
                {
                  position: [121.5273285, 31.21515044],
                  events: {
                    click: () => {
                      alert('click marker');
                    },
                    dragend: (e) => {
                      console.log('---event---: dragend')
                      this.markers[0].position = [e.lnglat.lng, e.lnglat.lat];
                    }
                  },
                  visible: true,
                  draggable: false,
                  template: '<span>1</span>',
                }
              ],
              renderMarker: {
                position: [121.5273285, 31.21715058],
                contentRender: (h, instance) => {
                  // if use jsx you can write in this
                  // return <div style={{background: '#80cbc4', whiteSpace: 'nowrap', border: 'solid #ddd 1px', color: '#f00'}} onClick={() => ...}>marker inner text</div>
                  return h(
                    'div',
                    {
                      style: {background: '#80cbc4', whiteSpace: 'nowrap', border: 'solid #ddd 1px', color: '#f00'},
                      on: {
                        click: () => {
                          const position = this.renderMarker.position;
                          this.renderMarker.position = [position[0] + 0.002, position[1] - 0.002];
                        }
                      }
                    },
                    ['marker inner text']
                  )
                }
              },
              componentMarker: {
                position: [121.5273285, 31.21315058],
                contentRender: (h, instance) => h(exampleComponents,{style: {backgroundColor: '#fff'}, props: {text: 'father is here'}}, ['xxxxxxx'])
              },
              slotMarker: {
                position: [121.5073285, 31.21715058]
              }
            };
          },
          methods: {
            onClick() {
              this.count += 1;
            },
            changePosition() {
              let position = this.markers[0].position;
              this.markers[0].position = [position[0] + 0.002, position[1] - 0.002];
            },
            chnageDraggle() {
              let draggable = this.markers[0].draggable;
              this.markers[0].draggable = !draggable;
            },
            toggleVisible() {
              let visableVar = this.markers[0].visible;
              this.markers[0].visible = !visableVar;
            },
            addMarker() {
              let marker = {
                position: [121.5273285 + (Math.random() - 0.5) * 0.02, 31.21515044 + (Math.random() - 0.5) * 0.02]
              };
              this.markers.push(marker);
            },
            removeMarker() {
              if (!this.markers.length) return;
              this.markers.splice(this.markers.length - 1, 1);
            }
          }
        };
    </script>

    4.3 weex-amap-info-window

    在這裏插入圖片描述

    <template>  
        <div class="amap-page-container">
          <el-amap vid="amap" :zoom="zoom" :center="center" class="amap-demo">
            <el-amap-info-window
              :position="currentWindow.position"
              :content="currentWindow.content"
              :visible="currentWindow.visible"
              :events="currentWindow.events">
            </el-amap-info-window>
          </el-amap>
          <button @click="switchWindow(0)">Show First Window</button>
          <button @click="switchWindow(1)">Show Second Window</button>
        </div>
      </template>
    
      <style>
        .amap-demo {
          height: 300px;
        }
      </style>
    
      <script>
        module.exports = {
          data () {
            return {
              zoom: 14,
              center: [121.5273285, 31.21515044],
              windows: [
                {
                  position: [121.5273285, 31.21515044],
                  content: 'Hi! I am here!',
                  visible: true,
                  events: {
                    close() {
                      console.log('close infowindow1');
                    }
                  }
                }, {
                  position: [121.5375285, 31.21515044],
                  content: 'Hi! I am here too!',
                  visible: true,
                  events: {
                    close() {
                      console.log('close infowindow2');
                    }
                  }
                }
              ],
              slotWindow: {
                position: [121.5163285, 31.21515044]
              },
              currentWindow: {
                position: [0, 0],
                content: '',
                events: {},
                visible: false
              }
            }
          },
    
          mounted() {
            this.currentWindow = this.windows[0];
          },
    
          methods: {
            switchWindow(tab) {
              this.currentWindow.visible = false;
              this.$nextTick(() => {
                this.currentWindow = this.windows[tab];
                this.currentWindow.visible = true;
              });
            }
          }
        };
    </script>

    API

    固然,除了組件以外,咱們還可使用weex-amap的API來直接操做地圖。

    5.1 騎行路徑Android實現

    - (void)searchRidingRouteFromLat:(int)fromLat fromLng:(int)fromLng toLat:(int)toLat toLng:(int)toLng {
    
        AMapRidingRouteSearchRequest *request = [[AMapRidingRouteSearchRequest alloc] init];
        request.origin = [AMapGeoPoint locationWithLatitude:INT_2_FLOAT(fromLat) / 1000000
                                                  longitude:INT_2_FLOAT(fromLng) / 1000000];
        request.destination = [AMapGeoPoint locationWithLatitude:INT_2_FLOAT(toLat) / 1000000
                                                       longitude:INT_2_FLOAT(toLng) / 1000000];
        //發起路徑搜索
        [self.aMapSearch AMapRidingRouteSearch:request];
    }
    
    - (void)onRouteSearchDone:(AMapRouteSearchBaseRequest *)request response:(AMapRouteSearchResponse *)response {
        if(response.route == nil) {
            return;
        }
        //經過AMapNavigationSearchResponse對象處理搜索結果
        AMapRoute *route = response.route;
        if (route.paths.count > 0) {
            AMapPath *amapPath = route.paths[0];
            NSArray *coordArray = amapPath.steps;
            NSMutableArray *mArray = [NSMutableArray array];
            NSArray *start = @[[NSString stringWithFormat:@"%f", request.origin.longitude], [NSString stringWithFormat:@"%f", request.origin.latitude]];
            [mArray insertObject:start atIndex:0];
            for (AMapStep *step in coordArray) {
                NSString *polistring = step.polyline;
                NSArray *array = [polistring componentsSeparatedByString:@";"];
                for (NSString *str in array) {
                    NSArray *loc =[str componentsSeparatedByString:@","];
                    [mArray addObject:loc];
                }
            }
            NSArray *end = @[[NSString stringWithFormat:@"%f", request.destination.longitude], [NSString stringWithFormat:@"%f", request.destination.latitude]];
            [mArray insertObject:end atIndex:mArray.count];
            [[DMessageChannelManager shared] postMessage:@"mapLines" andData:@{@"result": @"success", @"data": @{@"mapLines":mArray}}];
        }
    }
    
    - (void)AMapSearchRequest:(id)request didFailWithError:(NSError *)error
    {
        NSLog(@"Error: %@", error);
    }
    
    @end

    5.2 騎行路徑iOS實現

    private RouteTask.OnRouteCalculateListener calculateListener = new RouteTask.OnRouteCalculateListener() {
            @Override
            public void onRouteCalculate(RideRouteResult result, int code) {
                HashMap<String, Object> res = new HashMap<>(2);
                if (code == 1000 && result != null) {
                    Map<String, Object> data = new HashMap<>(1);
                    data.put("mapLines", getLatLngList(result.getPaths().get(0), routeTask.getStartPoint(), routeTask.getEndPoint()));
                    res.put("result", "success");
                    res.put("data", data);
                } else {
                    res.put("result", "fail");
                }
                String dataJson = new Gson().toJson(res);
                NotifyDataManager.getInstance().postMessage("mapLines", dataJson);
                WXLogUtils.d("RideRouteResult Json: " + dataJson);
            }
        };
             routeTask.addRouteCalculateListener(calculateListener);
    
        /**
         * 經過首尾經緯度計算走路規劃路徑中全部經緯度
         *
         * @param fromLat
         * @param fromLng
         * @param toLat
         * @param toLng
         */
        @JSMethod
        public void searchRidingRouteFromLat(float fromLat, float fromLng, float toLat, float toLng) {
            LocationEntity fromLe = new LocationEntity();
            fromLe.lat = fromLat / 1e6;
            fromLe.lng = fromLng / 1e6;
            LocationEntity toLe = new LocationEntity();
            toLe.lat = toLat / 1e6;
            toLe.lng = toLng / 1e6;
            if (routeTask == null) {
                routeTask = RouteTask.getInstance(mWXSDKInstance.getContext());
                routeTask.addRouteCalculateListener(calculateListener);
            }
            routeTask.search(fromLe, toLe);
        }

    5.3 騎行路徑Web實現

    let stream = weex.requireModule('stream')
        stream.fetch({
          timeout:20000,
          method: 'GET',
          url: 'https://restapi.amap.com/v4/direction/bicycling?key=87453539f02a65cd6585210fa2e64dc9&origin='+fromLng/1000000+','+fromLat/1000000+'&destination='+toLng/1000000+','+toLat/1000000,
      }, (response) => {
        if (response.status == 200) {
          let apiData = JSON.parse(response.data)
    
          if(apiData.data){
            var polyline= new Array(); 
            polyline[0] = apiData.data.origin.split(",");
            var polylineList = apiData.data.paths['0'].steps[0].polyline.split(";");
    
            for(var i=0;i<polylineList.length;i++) {
              var polylinePoint = polylineList[i].split(",");
              polyline.push(polylinePoint);
            }
            polyline.push(apiData.data.destination.split(",")); //字符分割 
            callback({"result":"success","data": {"mapLines":polyline}});
    
          }
        }
      }, () => {})
    相關文章
    相關標籤/搜索