[ios, macos] Snapshotter (runtime styling) delegates
Added a protocol and property for MGLMapSnapshotter’s delegate, which it uses for runtime styling. Generalized MGLStyle to be usable in the absence of MGLMapView. Moved MGLOpenGLStyleLayer code around to compile.
This commit is contained in:
committed by
Minh Nguyễn
parent
180ab72055
commit
63bf91125a
@@ -2,9 +2,12 @@
|
||||
#import "MGLTypes.h"
|
||||
#import "MGLGeometry.h"
|
||||
#import "MGLMapCamera.h"
|
||||
#import "MGLStyle.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol MGLMapSnapshotterDelegate;
|
||||
|
||||
/**
|
||||
An overlay that is placed within a `MGLMapSnapshot`.
|
||||
To access this object, use `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]`.
|
||||
@@ -177,8 +180,9 @@ typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapsh
|
||||
An `MGLMapSnapshotter` generates static raster images of the map. Each snapshot
|
||||
image depicts a portion of a map defined by an `MGLMapSnapshotOptions` object
|
||||
you provide. The snapshotter generates an `MGLMapSnapshot` object
|
||||
asynchronously, passing it into a completion handler once tiles and other
|
||||
resources needed for the snapshot are finished loading.
|
||||
asynchronously, calling `MGLMapSnapshotterDelegate` methods if defined, then
|
||||
passing it into a completion handler once tiles and other resources needed for
|
||||
the snapshot are finished loading.
|
||||
|
||||
You can change the snapshotter’s options at any time and reuse the snapshotter
|
||||
for multiple distinct snapshots; however, the snapshotter can only generate one
|
||||
@@ -220,7 +224,7 @@ typedef void (^MGLMapSnapshotCompletionHandler)(MGLMapSnapshot* _Nullable snapsh
|
||||
object's style, camera, and view bounds.
|
||||
*/
|
||||
MGL_EXPORT
|
||||
@interface MGLMapSnapshotter : NSObject
|
||||
@interface MGLMapSnapshotter : NSObject <MGLStylable>
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@@ -284,6 +288,78 @@ MGL_EXPORT
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
|
||||
|
||||
/**
|
||||
The snapshotter’s delegate.
|
||||
|
||||
The delegate is responsible for responding to significant changes during the
|
||||
snapshotting process, such as the style loading. Implement a delegate to
|
||||
customize the style that is depicted by the snapshot.
|
||||
|
||||
You set the delegate after initializing the snapshotter but before receiving
|
||||
the snapshot, typically before starting the snapshot. The snapshotter keeps a
|
||||
weak reference to its delegate, so you must keep a strong reference to it to
|
||||
ensure that your style customizations apply.
|
||||
*/
|
||||
@property (nonatomic, weak) id <MGLMapSnapshotterDelegate> delegate;
|
||||
|
||||
/**
|
||||
The style displayed in the resulting snapshot.
|
||||
|
||||
Unlike the `MGLMapSnapshotOptions.styleURL` property, this property is set to
|
||||
an object that allows you to manipulate every aspect of the style locally.
|
||||
|
||||
This property is set to `nil` until the style finishes loading. If the style
|
||||
has failed to load, this property is set to `nil`. Because the style loads
|
||||
asynchronously, you should manipulate it in the
|
||||
`-[MGLMapSnapshotterDelegate mapSnapshotter:didFinishLoadingStyle:]` method. It
|
||||
is not possible to manipulate the style before it has finished loading.
|
||||
|
||||
@note The default styles provided by Mapbox contain sources and layers with
|
||||
identifiers that will change over time. Applications that use APIs that
|
||||
manipulate a style’s sources and layers must first set the style URL to an
|
||||
explicitly versioned style using a convenience method like
|
||||
`+[MGLStyle outdoorsStyleURLWithVersion:]` or a manually constructed
|
||||
`NSURL`.
|
||||
*/
|
||||
@property (nonatomic, readonly, nullable) MGLStyle *style;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
Optional methods about significant events when creating a snapshot using an
|
||||
`MGLMapSnapshotter` object.
|
||||
*/
|
||||
@protocol MGLMapSnapshotterDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
Tells the delegate that the snapshotter was unable to load data needed for
|
||||
snapshotting the map.
|
||||
|
||||
This method may be called for a variety of reasons, including a network
|
||||
connection failure or a failure to fetch the style from the server. You can use
|
||||
the given error message to notify the user that map data is unavailable.
|
||||
|
||||
@param snapshotter The snapshotter that is unable to load the data.
|
||||
@param error The reason the data could not be loaded.
|
||||
*/
|
||||
- (void)mapSnapshotterDidFail:(MGLMapSnapshotter *)snapshotter withError:(NSError *)error;
|
||||
|
||||
/**
|
||||
Tells the delegate that the snapshotter has just finished loading a style.
|
||||
|
||||
This method is called in response to
|
||||
`-[MGLMapSnapshotter startWithQueue:completionHandler:]` as long as the
|
||||
`MGLMapSnapshotter.delegate` property is set. Changes to sources or layers of
|
||||
the style being snapshotted do not cause this method to be called.
|
||||
|
||||
@param snapshotter The snapshotter that has just loaded a style.
|
||||
@param style The style that was loaded.
|
||||
*/
|
||||
- (void)mapSnapshotter:(MGLMapSnapshotter *)snapshotter didFinishLoadingStyle:(MGLStyle *)style;
|
||||
|
||||
- (void)mapSnapshotter:(MGLMapSnapshotter *)snapshotter didFailLoadingImageNamed:(NSString *)name;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
|
||||
#import "MGLOfflineStorage_Private.h"
|
||||
#import "MGLGeometry_Private.h"
|
||||
#import "NSBundle+MGLAdditions.h"
|
||||
#import "MGLStyle.h"
|
||||
#import "MGLStyle_Private.h"
|
||||
#import "MGLAttributionInfo_Private.h"
|
||||
#import "MGLLoggingConfiguration_Private.h"
|
||||
#import "MGLRendererConfiguration.h"
|
||||
@@ -30,6 +29,8 @@
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#endif
|
||||
|
||||
#import "NSBundle+MGLAdditions.h"
|
||||
|
||||
const CGPoint MGLLogoImagePosition = CGPointMake(8, 8);
|
||||
const CGFloat MGLSnapshotterMinimumPixelSize = 64;
|
||||
|
||||
@@ -37,6 +38,41 @@ MGLImage *MGLAttributedSnapshot(mbgl::MapSnapshotter::Attributions attributions,
|
||||
MGLMapSnapshot *MGLSnapshotWithDecoratedImage(MGLImage *mglImage, MGLMapSnapshotOptions *options, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn, mbgl::MapSnapshotter::LatLngForFn latLngForFn, MGLMapSnapshotOverlayHandler overlayHandler, NSError * _Nullable *outError);
|
||||
NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnapshotter::Attributions attributions);
|
||||
|
||||
class MGLMapSnapshotterDelegateHost: public mbgl::MapSnapshotterObserver {
|
||||
public:
|
||||
MGLMapSnapshotterDelegateHost(MGLMapSnapshotter *snapshotter_) : snapshotter(snapshotter_) {}
|
||||
|
||||
void onDidFailLoadingStyle(const std::string& errorMessage) {
|
||||
MGLMapSnapshotter *strongSnapshotter = snapshotter;
|
||||
if ([strongSnapshotter.delegate respondsToSelector:@selector(mapSnapshotterDidFail:withError:)]) {
|
||||
NSString *description = @(errorMessage.c_str());
|
||||
NSDictionary *userInfo = @{
|
||||
NSLocalizedDescriptionKey: NSLocalizedStringWithDefaultValue(@"SNAPSHOT_LOAD_STYLE_FAILED_DESC", nil, nil, @"The snapshot failed because the style can’t be loaded.", @"User-friendly error description"),
|
||||
NSLocalizedFailureReasonErrorKey: description,
|
||||
};
|
||||
NSError *error = [NSError errorWithDomain:MGLErrorDomain code:MGLErrorCodeLoadStyleFailed userInfo:userInfo];
|
||||
[strongSnapshotter.delegate mapSnapshotterDidFail:snapshotter withError:error];
|
||||
}
|
||||
}
|
||||
|
||||
void onDidFinishLoadingStyle() {
|
||||
MGLMapSnapshotter *strongSnapshotter = snapshotter;
|
||||
if ([strongSnapshotter.delegate respondsToSelector:@selector(mapSnapshotter:didFinishLoadingStyle:)]) {
|
||||
[strongSnapshotter.delegate mapSnapshotter:snapshotter didFinishLoadingStyle:snapshotter.style];
|
||||
}
|
||||
}
|
||||
|
||||
void onStyleImageMissing(const std::string& imageName) {
|
||||
MGLMapSnapshotter *strongSnapshotter = snapshotter;
|
||||
if ([strongSnapshotter.delegate respondsToSelector:@selector(mapSnapshotter:didFailLoadingImageNamed:)]) {
|
||||
[strongSnapshotter.delegate mapSnapshotter:snapshotter didFailLoadingImageNamed:@(imageName.c_str())];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
__weak MGLMapSnapshotter *snapshotter;
|
||||
};
|
||||
|
||||
@interface MGLMapSnapshotOverlay() <MGLMapSnapshotProtocol>
|
||||
@property (nonatomic, assign) CGFloat scale;
|
||||
- (instancetype)initWithContext:(CGContextRef)context scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn;
|
||||
@@ -208,6 +244,7 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
|
||||
|
||||
@implementation MGLMapSnapshotter {
|
||||
std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter;
|
||||
std::unique_ptr<MGLMapSnapshotterDelegateHost> _delegateHost;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
@@ -660,6 +697,7 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
|
||||
_mbglMapSnapshotter->cancel();
|
||||
}
|
||||
_mbglMapSnapshotter.reset();
|
||||
_delegateHost.reset();
|
||||
}
|
||||
|
||||
- (void)configureWithOptions:(MGLMapSnapshotOptions *)options {
|
||||
@@ -682,8 +720,9 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
|
||||
.withAssetPath(NSBundle.mainBundle.resourceURL.path.UTF8String);
|
||||
|
||||
// Create the snapshotter
|
||||
_delegateHost = std::make_unique<MGLMapSnapshotterDelegateHost>(self);
|
||||
_mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(
|
||||
size, pixelRatio, resourceOptions, mbgl::MapSnapshotterObserver::nullObserver(), config.localFontFamilyName);
|
||||
size, pixelRatio, resourceOptions, *_delegateHost, config.localFontFamilyName);
|
||||
|
||||
_mbglMapSnapshotter->setStyleURL(std::string(options.styleURL.absoluteString.UTF8String));
|
||||
|
||||
@@ -703,4 +742,11 @@ NSArray<MGLAttributionInfo *> *MGLAttributionInfosFromAttributions(mbgl::MapSnap
|
||||
}
|
||||
}
|
||||
|
||||
- (MGLStyle *)style {
|
||||
if (!_mbglMapSnapshotter) {
|
||||
return nil;
|
||||
}
|
||||
return [[MGLStyle alloc] initWithRawStyle:&_mbglMapSnapshotter->getStyle() stylable:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -9,48 +9,7 @@
|
||||
#include <mbgl/gl/custom_layer.hpp>
|
||||
#include <mbgl/math/wrap.hpp>
|
||||
|
||||
class MGLOpenGLLayerHost : public mbgl::style::CustomLayerHost {
|
||||
public:
|
||||
MGLOpenGLLayerHost(MGLOpenGLStyleLayer *styleLayer) {
|
||||
layerRef = styleLayer;
|
||||
layer = nil;
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
if (layerRef == nil) return;
|
||||
else if (layer == nil) layer = layerRef;
|
||||
|
||||
[layer didMoveToMapView:layer.style.mapView];
|
||||
}
|
||||
|
||||
void render(const mbgl::style::CustomLayerRenderParameters ¶ms) {
|
||||
if(!layer) return;
|
||||
|
||||
MGLStyleLayerDrawingContext drawingContext = {
|
||||
.size = CGSizeMake(params.width, params.height),
|
||||
.centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude),
|
||||
.zoomLevel = params.zoom,
|
||||
.direction = mbgl::util::wrap(params.bearing, 0., 360.),
|
||||
.pitch = static_cast<CGFloat>(params.pitch),
|
||||
.fieldOfView = static_cast<CGFloat>(params.fieldOfView),
|
||||
.projectionMatrix = MGLMatrix4Make(params.projectionMatrix)
|
||||
};
|
||||
[layer drawInMapView:layer.style.mapView withContext:drawingContext];
|
||||
}
|
||||
|
||||
void contextLost() {}
|
||||
|
||||
void deinitialize() {
|
||||
if (layer == nil) return;
|
||||
|
||||
[layer willMoveFromMapView:layer.style.mapView];
|
||||
layerRef = layer;
|
||||
layer = nil;
|
||||
}
|
||||
private:
|
||||
__weak MGLOpenGLStyleLayer * layerRef;
|
||||
MGLOpenGLStyleLayer * layer = nil;
|
||||
};
|
||||
class MGLOpenGLLayerHost;
|
||||
|
||||
/**
|
||||
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code that
|
||||
@@ -74,6 +33,8 @@ private:
|
||||
|
||||
@property (nonatomic, readonly) mbgl::style::CustomLayer *rawLayer;
|
||||
|
||||
@property (nonatomic, readonly, nullable) MGLMapView *mapView;
|
||||
|
||||
/**
|
||||
The style currently containing the layer.
|
||||
|
||||
@@ -107,13 +68,20 @@ private:
|
||||
return (mbgl::style::CustomLayer *)super.rawLayer;
|
||||
}
|
||||
|
||||
- (MGLMapView *)mapView {
|
||||
if ([self.style.stylable isKindOfClass:[MGLMapView class]]) {
|
||||
return (MGLMapView *)self.style.stylable;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
- (EAGLContext *)context {
|
||||
return self.style.mapView.context;
|
||||
return self.mapView.context;
|
||||
}
|
||||
#else
|
||||
- (CGLContextObj)context {
|
||||
return self.style.mapView.context;
|
||||
return self.mapView.context;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -191,11 +159,60 @@ private:
|
||||
causing the `-drawInMapView:withContext:` method to be called.
|
||||
*/
|
||||
- (void)setNeedsDisplay {
|
||||
[self.style.mapView setNeedsRerender];
|
||||
[self.mapView setNeedsRerender];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
class MGLOpenGLLayerHost : public mbgl::style::CustomLayerHost {
|
||||
public:
|
||||
MGLOpenGLLayerHost(MGLOpenGLStyleLayer *styleLayer) {
|
||||
layerRef = styleLayer;
|
||||
layer = nil;
|
||||
}
|
||||
|
||||
void initialize() {
|
||||
if (layerRef == nil) return;
|
||||
else if (layer == nil) layer = layerRef;
|
||||
|
||||
if (layer.mapView) {
|
||||
[layer didMoveToMapView:layer.mapView];
|
||||
}
|
||||
}
|
||||
|
||||
void render(const mbgl::style::CustomLayerRenderParameters ¶ms) {
|
||||
if(!layer) return;
|
||||
|
||||
MGLStyleLayerDrawingContext drawingContext = {
|
||||
.size = CGSizeMake(params.width, params.height),
|
||||
.centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude),
|
||||
.zoomLevel = params.zoom,
|
||||
.direction = mbgl::util::wrap(params.bearing, 0., 360.),
|
||||
.pitch = static_cast<CGFloat>(params.pitch),
|
||||
.fieldOfView = static_cast<CGFloat>(params.fieldOfView),
|
||||
.projectionMatrix = MGLMatrix4Make(params.projectionMatrix)
|
||||
};
|
||||
if (layer.mapView) {
|
||||
[layer drawInMapView:layer.mapView withContext:drawingContext];
|
||||
}
|
||||
}
|
||||
|
||||
void contextLost() {}
|
||||
|
||||
void deinitialize() {
|
||||
if (layer == nil) return;
|
||||
|
||||
if (layer.mapView) {
|
||||
[layer willMoveFromMapView:layer.mapView];
|
||||
}
|
||||
layerRef = layer;
|
||||
layer = nil;
|
||||
}
|
||||
private:
|
||||
__weak MGLOpenGLStyleLayer * layerRef;
|
||||
MGLOpenGLStyleLayer * layer = nil;
|
||||
};
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
MGLStyleLayer* OpenGLStyleLayerPeerFactory::createPeer(style::Layer* rawLayer) {
|
||||
|
||||
@@ -243,8 +243,9 @@ mbgl::Immutable<mbgl::style::GeoJSONOptions> MGLGeoJSONOptionsFromDictionary(NSD
|
||||
}
|
||||
|
||||
std::vector<mbgl::Feature> features;
|
||||
if (self.mapView) {
|
||||
features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
|
||||
if ([self.stylable isKindOfClass:[MGLMapView class]]) {
|
||||
MGLMapView *mapView = (MGLMapView *)self.stylable;
|
||||
features = mapView.renderer->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
|
||||
}
|
||||
return MGLFeaturesFromMBGLFeatures(features);
|
||||
}
|
||||
@@ -256,7 +257,7 @@ mbgl::Immutable<mbgl::style::GeoJSONOptions> MGLGeoJSONOptionsFromDictionary(NSD
|
||||
mbgl::optional<mbgl::FeatureExtensionValue> extensionValue;
|
||||
|
||||
// Check parameters
|
||||
if (!self.rawSource || !self.mapView || !cluster) {
|
||||
if (!self.rawSource || !self.stylable || !cluster) {
|
||||
return extensionValue;
|
||||
}
|
||||
|
||||
@@ -269,11 +270,14 @@ mbgl::Immutable<mbgl::style::GeoJSONOptions> MGLGeoJSONOptionsFromDictionary(NSD
|
||||
|
||||
auto clusterFeature = geoJSON.get<mbgl::GeoJSONFeature>();
|
||||
|
||||
extensionValue = self.mapView.renderer->queryFeatureExtensions(self.rawSource->getID(),
|
||||
clusterFeature,
|
||||
"supercluster",
|
||||
extension,
|
||||
options);
|
||||
if ([self.stylable isKindOfClass:[MGLMapView class]]) {
|
||||
MGLMapView *mapView = (MGLMapView *)self.stylable;
|
||||
extensionValue = mapView.renderer->queryFeatureExtensions(self.rawSource->getID(),
|
||||
clusterFeature,
|
||||
"supercluster",
|
||||
extension,
|
||||
options);
|
||||
}
|
||||
return extensionValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
|
||||
// special internal source types like mbgl::AnnotationSource.
|
||||
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
|
||||
|
||||
@property (nonatomic, readonly, weak) MGLMapView *mapView;
|
||||
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
|
||||
|
||||
@end
|
||||
|
||||
@@ -37,12 +37,12 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(MGLMapView *)mapView {
|
||||
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource stylable:(id <MGLStylable>)stylable {
|
||||
NSString *identifier = @(rawSource->getID().c_str());
|
||||
if (self = [self initWithIdentifier:identifier]) {
|
||||
_weakSource = rawSource->makeWeakPtr();
|
||||
rawSource->peer = SourceWrapper { self };
|
||||
_mapView = mapView;
|
||||
_stylable = stylable;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -53,24 +53,24 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
|
||||
}
|
||||
|
||||
- (instancetype)initWithPendingSource:(std::unique_ptr<mbgl::style::Source>)pendingSource {
|
||||
if (self = [self initWithRawSource:pendingSource.get() mapView:nil]) {
|
||||
if (self = [self initWithRawSource:pendingSource.get() stylable:nil]) {
|
||||
_pendingSource = std::move(pendingSource);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addToMapView:(MGLMapView *)mapView {
|
||||
- (void)addToStylable:(id <MGLStylable>)stylable {
|
||||
if (_pendingSource == nullptr) {
|
||||
[NSException raise:MGLRedundantSourceException
|
||||
format:@"This instance %@ was already added to %@. Adding the same source instance " \
|
||||
"to the style more than once is invalid.", self, mapView.style];
|
||||
"to the style more than once is invalid.", self, stylable.style];
|
||||
}
|
||||
|
||||
_mapView = mapView;
|
||||
_mapView.style.rawStyle->addSource(std::move(_pendingSource));
|
||||
_stylable = stylable;
|
||||
_stylable.style.rawStyle->addSource(std::move(_pendingSource));
|
||||
}
|
||||
|
||||
- (BOOL)removeFromMapView:(MGLMapView *)mapView error:(NSError * __nullable * __nullable)outError {
|
||||
- (BOOL)removeFromStylable:(id <MGLStylable>)mapView error:(NSError * __nullable * __nullable)outError {
|
||||
MGLAssertStyleSourceIsValid();
|
||||
BOOL removed = NO;
|
||||
|
||||
@@ -81,7 +81,7 @@ const MGLExceptionName MGLInvalidStyleSourceException = @"MGLInvalidStyleSourceE
|
||||
if (removedSource) {
|
||||
removed = YES;
|
||||
_pendingSource = std::move(removedSource);
|
||||
_mapView = nil;
|
||||
_stylable = nil;
|
||||
} else if (outError) {
|
||||
NSString *localizedDescription = [NSString stringWithFormat:
|
||||
NSLocalizedStringWithDefaultValue(@"REMOVE_SRC_FAIL_IN_USE_FMT", @"Foundation", nil, @"The source “%@” can’t be removed while it is in use.", @"User-friendly error description; first placeholder is the source’s identifier"),
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol MGLStylable;
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
class Source;
|
||||
@@ -41,7 +43,7 @@ do { \
|
||||
Initializes and returns a source with a raw pointer to the backing store,
|
||||
associated with a style.
|
||||
*/
|
||||
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource mapView:(nullable MGLMapView *)mapView;
|
||||
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource stylable:(nullable id <MGLStylable>)stylable;
|
||||
|
||||
/**
|
||||
Initializes and returns a source with an owning pointer to the backing store,
|
||||
@@ -59,11 +61,12 @@ do { \
|
||||
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
|
||||
|
||||
/**
|
||||
The map view whose style currently contains the source.
|
||||
If the source is not currently part of any map view’s style, this property is
|
||||
set to `nil`.
|
||||
The stylable object whose style currently contains the source.
|
||||
|
||||
If the source is not currently part of any stylable object’s style, this
|
||||
property is set to `nil`.
|
||||
*/
|
||||
@property (nonatomic, readonly, weak) MGLMapView *mapView;
|
||||
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
|
||||
|
||||
/**
|
||||
Adds the mbgl source that this object represents to the mbgl map.
|
||||
@@ -74,7 +77,7 @@ do { \
|
||||
is added back to the map via `-[MGLStyle addSource:]` and styled with a
|
||||
`MGLLayer`.
|
||||
*/
|
||||
- (void)addToMapView:(MGLMapView *)mapView;
|
||||
- (void)addToStylable:(id <MGLStylable>)mapView;
|
||||
|
||||
/**
|
||||
Removes the mbgl source that this object represents from the mbgl map.
|
||||
@@ -82,7 +85,7 @@ do { \
|
||||
to the `MGLSource` instance and the unique_ptr reference is valid again. It is
|
||||
safe to add the source back to the style after it is removed.
|
||||
*/
|
||||
- (BOOL)removeFromMapView:(MGLMapView *)mapView error:(NSError * __nullable * __nullable)outError;
|
||||
- (BOOL)removeFromStylable:(id <MGLStylable>)mapView error:(NSError * __nullable * __nullable)outError;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -539,4 +539,24 @@ MGL_EXPORT
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
An object whose contents are represented by an `MGLStyle` object that you
|
||||
configure.
|
||||
*/
|
||||
@protocol MGLStylable <NSObject>
|
||||
|
||||
/**
|
||||
The style currently displayed in the receiver.
|
||||
|
||||
@note The default styles provided by Mapbox contain sources and layers with
|
||||
identifiers that will change over time. Applications that use APIs that
|
||||
manipulate a style’s sources and layers must first set the style URL to an
|
||||
explicitly versioned style using a convenience method like
|
||||
`+[MGLStyle outdoorsStyleURLWithVersion:]` or a manually constructed
|
||||
`NSURL`.
|
||||
*/
|
||||
@property (nonatomic, readonly, nullable) MGLStyle *style;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -77,7 +77,7 @@ const MGLExceptionName MGLRedundantSourceIdentifierException = @"MGLRedundantSou
|
||||
|
||||
@interface MGLStyle()
|
||||
|
||||
@property (nonatomic, readonly, weak) MGLMapView *mapView;
|
||||
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
|
||||
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
|
||||
@property (readonly, copy, nullable) NSURL *URL;
|
||||
@property (nonatomic, readwrite, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
|
||||
@@ -119,14 +119,14 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView {
|
||||
MGLLogInfo(@"Initializing %@ with mapView: %@", NSStringFromClass([self class]), mapView);
|
||||
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle stylable:(id <MGLStylable>)stylable {
|
||||
MGLLogInfo(@"Initializing %@ with stylable: %@", NSStringFromClass([self class]), stylable);
|
||||
if (self = [super init]) {
|
||||
_mapView = mapView;
|
||||
_stylable = stylable;
|
||||
_rawStyle = rawStyle;
|
||||
_openGLLayers = [NSMutableDictionary dictionary];
|
||||
_localizedLayersByIdentifier = [NSMutableDictionary dictionary];
|
||||
MGLLogDebug(@"Initializing with style name: %@ mapView: %@", self.name, mapView);
|
||||
MGLLogDebug(@"Initializing with style name: %@ stylable: %@", self.name, stylable);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -186,17 +186,17 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
|
||||
// TODO: Fill in options specific to the respective source classes
|
||||
// https://github.com/mapbox/mapbox-gl-native/issues/6584
|
||||
if (auto vectorSource = rawSource->as<mbgl::style::VectorSource>()) {
|
||||
return [[MGLVectorTileSource alloc] initWithRawSource:vectorSource mapView:self.mapView];
|
||||
return [[MGLVectorTileSource alloc] initWithRawSource:vectorSource stylable:self.stylable];
|
||||
} else if (auto geoJSONSource = rawSource->as<mbgl::style::GeoJSONSource>()) {
|
||||
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource mapView:self.mapView];
|
||||
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource stylable:self.stylable];
|
||||
} else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
|
||||
return [[MGLRasterTileSource alloc] initWithRawSource:rasterSource mapView:self.mapView];
|
||||
return [[MGLRasterTileSource alloc] initWithRawSource:rasterSource stylable:self.stylable];
|
||||
} else if (auto rasterDEMSource = rawSource->as<mbgl::style::RasterDEMSource>()) {
|
||||
return [[MGLRasterDEMSource alloc] initWithRawSource:rasterDEMSource mapView:self.mapView];
|
||||
return [[MGLRasterDEMSource alloc] initWithRawSource:rasterDEMSource stylable:self.stylable];
|
||||
} else if (auto imageSource = rawSource->as<mbgl::style::ImageSource>()) {
|
||||
return [[MGLImageSource alloc] initWithRawSource:imageSource mapView:self.mapView];
|
||||
return [[MGLImageSource alloc] initWithRawSource:imageSource stylable:self.stylable];
|
||||
} else {
|
||||
return [[MGLSource alloc] initWithRawSource:rawSource mapView:self.mapView];
|
||||
return [[MGLSource alloc] initWithRawSource:rawSource stylable:self.stylable];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
|
||||
}
|
||||
|
||||
try {
|
||||
[source addToMapView:self.mapView];
|
||||
[source addToStylable:self.stylable];
|
||||
} catch (std::runtime_error & err) {
|
||||
[NSException raise:MGLRedundantSourceIdentifierException format:@"%s", err.what()];
|
||||
}
|
||||
@@ -243,7 +243,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
|
||||
}
|
||||
}
|
||||
|
||||
return [source removeFromMapView:self.mapView error:outError];
|
||||
return [source removeFromStylable:self.stylable error:outError];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ namespace mbgl {
|
||||
|
||||
@interface MGLStyle (Private)
|
||||
|
||||
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView;
|
||||
- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle stylable:(id <MGLStylable>)stylable;
|
||||
|
||||
@property (nonatomic, readonly, weak) MGLMapView *mapView;
|
||||
@property (nonatomic, readonly, weak) id <MGLStylable> stylable;
|
||||
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
|
||||
|
||||
- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
|
||||
|
||||
@@ -72,8 +72,9 @@
|
||||
}
|
||||
|
||||
std::vector<mbgl::Feature> features;
|
||||
if (self.mapView) {
|
||||
features = self.mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
|
||||
if ([self.stylable isKindOfClass:[MGLMapView class]]) {
|
||||
MGLMapView *mapView = (MGLMapView *)self.stylable;
|
||||
features = mapView.renderer->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
|
||||
}
|
||||
return MGLFeaturesFromMBGLFeatures(features);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
|
||||
|
||||
### Snapshots
|
||||
|
||||
* Added the `MGLMapSnapshotter.delegate` property and `MGLMapSnapshotterDelegate` protocol for customizing the style before taking a snapshot. ([#235](https://github.com/mapbox/mapbox-gl-native-ios/pull/235))
|
||||
* You no longer need to explicitly capture the `MGLMapSnapshotter` object in the completion handler that you specify in `-[MGLMapSnapshotter startWithCompletionHandler:]`. Even if you declare the snapshotter locally without holding a strong reference to it, the snapshotter is only deallocated after the completion handler finishes, and the completion handler generally receives a valid snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
|
||||
* The `-[MGLMapSnapshotter cancel]` method no longer calls the completion handler passed into `-[MGLMapSnapshotter startWithCompletionHandler:]`. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
|
||||
* Fixed an issue where the `MGLMapSnapshotter.loading` property always returned `NO`, even while loading a snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
|
||||
|
||||
@@ -50,7 +50,7 @@ void MGLMapViewImpl::onDidFailLoadingMap(mbgl::MapLoadError mapError, const std:
|
||||
break;
|
||||
case mbgl::MapLoadError::StyleLoadError:
|
||||
code = MGLErrorCodeLoadStyleFailed;
|
||||
description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can't be loaded.", @"User-friendly error description");
|
||||
description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can’t be loaded.", @"User-friendly error description");
|
||||
break;
|
||||
case mbgl::MapLoadError::NotFoundError:
|
||||
code = MGLErrorCodeNotFound;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#import "MGLGeometry.h"
|
||||
#import "MGLMapCamera.h"
|
||||
#import "MGLTypes.h"
|
||||
#import "MGLStyle.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -14,7 +15,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@class MGLPolyline;
|
||||
@class MGLPolygon;
|
||||
@class MGLShape;
|
||||
@class MGLStyle;
|
||||
|
||||
@protocol MGLMapViewDelegate;
|
||||
@protocol MGLAnnotation;
|
||||
@@ -188,7 +188,7 @@ FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLUserLocationAnnotationTyp
|
||||
Simple map view</a> example to learn how to initialize a basic `MGLMapView`.
|
||||
*/
|
||||
MGL_EXPORT
|
||||
@interface MGLMapView : UIView
|
||||
@interface MGLMapView : UIView <MGLStylable>
|
||||
|
||||
#pragma mark Creating Instances
|
||||
|
||||
|
||||
@@ -6459,7 +6459,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
self.style = [[MGLStyle alloc] initWithRawStyle:&self.mbglMap.getStyle() mapView:self];
|
||||
self.style = [[MGLStyle alloc] initWithRawStyle:&self.mbglMap.getStyle() stylable:self];
|
||||
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
|
||||
{
|
||||
[self.delegate mapView:self didFinishLoadingStyle:self.style];
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
### Snapshots
|
||||
|
||||
* Added an `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]` method to provide the snapshot's current `CGContext` in order to perform custom drawing on `MGLMapSnapshot` objects. ([#15530](https://github.com/mapbox/mapbox-gl-native/pull/15530))
|
||||
* Added the `MGLMapSnapshotter.delegate` property and `MGLMapSnapshotterDelegate` protocol for customizing the style before taking a snapshot. ([#235](https://github.com/mapbox/mapbox-gl-native-ios/pull/235))
|
||||
* You no longer need to explicitly capture the `MGLMapSnapshotter` object in the completion handler that you specify in `-[MGLMapSnapshotter startWithCompletionHandler:]`. Even if you declare the snapshotter locally without holding a strong reference to it, the snapshotter is only deallocated after the completion handler finishes, and the completion handler generally receives a valid snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
|
||||
* The `-[MGLMapSnapshotter cancel]` method no longer calls the completion handler passed into `-[MGLMapSnapshotter startWithCompletionHandler:]`. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
|
||||
* Fixed an issue where the `MGLMapSnapshotter.loading` property always returned `NO`, even while loading a snapshot. ([#210](https://github.com/mapbox/mapbox-gl-native-ios/pull/210))
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
#import "MGLFoundation.h"
|
||||
#import "MGLTypes.h"
|
||||
#import "MGLGeometry.h"
|
||||
#import "MGLStyle.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class MGLAnnotationImage;
|
||||
@class MGLMapCamera;
|
||||
@class MGLStyle;
|
||||
@class MGLShape;
|
||||
|
||||
@protocol MGLAnnotation;
|
||||
@@ -65,7 +65,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
ensuring that your use adheres to the relevant terms of use.
|
||||
*/
|
||||
MGL_EXPORT IB_DESIGNABLE
|
||||
@interface MGLMapView : NSView
|
||||
@interface MGLMapView : NSView <MGLStylable>
|
||||
|
||||
#pragma mark Creating Instances
|
||||
|
||||
|
||||
@@ -961,7 +961,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() mapView:self];
|
||||
self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() stylable:self];
|
||||
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
|
||||
{
|
||||
[self.delegate mapView:self didFinishLoadingStyle:self.style];
|
||||
|
||||
Reference in New Issue
Block a user