From 44eee848c4f62d50a038f71743f638f5e9bfc307 Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Mon, 15 Mar 2021 21:46:26 -0700 Subject: [PATCH 01/16] Symbol Layer Styling debugging. --- .../CustomPointAnnotationExample.swift | 241 ++++++++++++++++++ .../Contents.json | 12 + .../RouteInfoAnnotationLeftHanded.png | Bin 0 -> 2391 bytes .../Contents.json | 12 + .../RouteInfoAnnotationRightHanded.png | Bin 0 -> 2463 bytes 5 files changed, 265 insertions(+) create mode 100644 Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json create mode 100644 Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png create mode 100644 Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json create mode 100644 Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png diff --git a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift index 6587e4b7f7b6..938ebf4f149b 100644 --- a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift @@ -1,8 +1,23 @@ import UIKit import MapboxMaps +import Turf @objc(CustomPointAnnotationExample) +fileprivate enum RouteDurationAnnotationTailPosition: Int { + case left + case right +} + +fileprivate struct DebugFeature { + var coordinate: CLLocationCoordinate2D + var selected: Bool + var sortOrder: Int + var tailPosition: RouteDurationAnnotationTailPosition + var label: String + var imageName: String +} + public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { internal var mapView: MapView! @@ -18,6 +33,8 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { mapView = MapView(frame: view.bounds, mapInitOptions: options) mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(mapView) + mapView.cameraManager.setCamera(centerCoordinate: centerCoordinate, + zoom: 15.0) // Allows the delegate to receive information about map events. mapView.mapboxMap.onNext(.mapLoaded) { [weak self] _ in @@ -35,8 +52,232 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { // Add the annotation to the map. self.mapView.annotations.addAnnotation(customPointAnnotation) + self.updateAnnotationSymbolImages() + let features = self.addDebugFeatures() + self.addRouteAnnotationSymbolLayer(features: features) + // The below line is used for internal testing purposes only. self.finish() } } + + private func updateAnnotationSymbolImages() { + guard let style = mapView.style, style.getStyleImage(with: "RouteInfoAnnotationLeftHanded") == nil, style.getStyleImage(with: "RouteInfoAnnotationRightHanded") == nil else { return } + + let routeDurationAnnotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) + let routeDurationAnnotationColor = UIColor.white + + // Right-hand pin + if let image = UIImage(named: "RouteInfoAnnotationRightHanded") { + let regularRouteImage = image.tint(routeDurationAnnotationColor) + + let lStretchX = ImageStretches(first: Float(32), second: Float(42)) + let stretchX = [lStretchX] + let stretchY = [ImageStretches(first: Float(26), second: Float(32))] + let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) + + style.setStyleImage(image: regularRouteImage, + with: "RouteInfoAnnotationRightHanded", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + + let selectedRouteImage = image.tint(routeDurationAnnotationSelectedColor) + style.setStyleImage(image: selectedRouteImage, + with: "RouteInfoAnnotationRightHanded-Selected", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + } + + // Left-hand pin + if let image = UIImage(named: "RouteInfoAnnotationLeftHanded") { + let regularRouteImage = image.tint(routeDurationAnnotationColor) + + let lStretchX = ImageStretches(first: Float(32), second: Float(42)) + let stretchX = [lStretchX] + let stretchY = [ImageStretches(first: Float(26), second: Float(32))] + let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) + + style.setStyleImage(image: regularRouteImage, + with: "RouteInfoAnnotationLeftHanded", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + + let selectedRouteImage = image.tint(routeDurationAnnotationSelectedColor) + style.setStyleImage(image: selectedRouteImage, + with: "RouteInfoAnnotationLeftHanded-Selected", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + } + } + + static let routeDurationAnnotations = "routeDurationAnnotations" + + private func addDebugFeatures() -> FeatureCollection { + var features = [Feature]() + let featureList = [ + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), selected: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway Lefthand Stem", imageName: "RouteInfoAnnotationLeftHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), selected: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John Righthand Stem", imageName: "RouteInfoAnnotationRightHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716908, -74.004016), selected: true, sortOrder: 1, tailPosition: .right, label: "Leonard & Broadway Selected Right", imageName: "RouteInfoAnnotationRightHanded-Selected"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), selected: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold Selected Left", imageName: "RouteInfoAnnotationLeftHanded-Selected") + ] + + for (index, feature) in featureList.enumerated() { + var featurePoint = Feature(Point(feature.coordinate)) + + // set the feature attributes which will be used in styling the symbol style layer + featurePoint.properties = ["selected": feature.selected, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, "imageName": feature.imageName, "sortOrder": feature.selected == true ? 1 : -index] + + features.append(featurePoint) + } + + return FeatureCollection(features: features) + } + + private func addRouteAnnotationSymbolLayer(features: FeatureCollection) { + guard let style = mapView.style else { return } + if let _ = try? mapView.style.getSource(identifier: CustomPointAnnotationExample.routeDurationAnnotations, type: GeoJSONSource.self).get() { + let _ = mapView.style.updateGeoJSON(for: CustomPointAnnotationExample.routeDurationAnnotations, with: features) + } else { + + var dataSource = GeoJSONSource() + dataSource.data = .featureCollection(features) + mapView.style.addSource(source: dataSource, identifier: CustomPointAnnotationExample.routeDurationAnnotations) + } + + var shapeLayer: SymbolLayer + + if let layer = try? mapView.style.getLayer(with: CustomPointAnnotationExample.routeDurationAnnotations, type: SymbolLayer.self).get() { + shapeLayer = layer + } else { + shapeLayer = SymbolLayer(id: CustomPointAnnotationExample.routeDurationAnnotations) + } + + shapeLayer.source = CustomPointAnnotationExample.routeDurationAnnotations + + shapeLayer.layout?.textField = .expression(Exp(.get) { + "text" + }) + + shapeLayer.layout?.iconImage = .expression(Exp(.get) { + "imageName" + }) + + shapeLayer.paint?.textColor = .expression(Exp(.switchCase) { + Exp(.any) { + Exp(.get) { + "selected" + } + } + UIColor.white + UIColor.black + }) + + shapeLayer.layout?.textSize = .expression( + Exp(.interpolate) { + Exp(.linear) + Exp(.zoom) + 13 + 16 + 15.5 + 20 + } + ) + + shapeLayer.layout?.iconTextFit = .both + shapeLayer.layout?.iconAllowOverlap = .constant(true) + shapeLayer.layout?.textAllowOverlap = .constant(true) + shapeLayer.layout?.textJustify = .left + shapeLayer.layout?.symbolZOrder = .auto + shapeLayer.layout?.textFont = .constant(["DIN Pro Medium"]) +// shapeLayer.layout?.iconTextFitPadding = .constant([-4.0, -4.0, -2.0, -4.0]) + shapeLayer.layout?.symbolSortKey = .expression(Exp(.switchCase) { + Exp(.any) { + Exp(.get) { + "selected" + } + } + 1.0 + 0.0 + }) + + style.addLayer(layer: shapeLayer, layerPosition: nil) + + let expressionString = + """ + [ + "match", + ["get", "tailPosition"], + ["0"], + "bottom-left", + "bottom-right" + ] + """ + + if let expressionData = expressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + property: "icon-anchor", + value: expJSONObject) + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + property: "text-anchor", + value: expJSONObject) + } + + let offsetExpressionString = + """ + [ + "match", + ["get", "tailPosition"], + ["0"], + ["literal", [0.5, -1]], + ["literal", [-0.5, -1]] + ] + """ + + if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + property: "icon-offset", + value: expJSONObject) + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + property: "text-offset", + value: expJSONObject) + } + } +} + +extension UIImage { + func tint(_ tintColor: UIColor) -> UIImage { + let imageSize = size + let imageScale = scale + let contextBounds = CGRect(origin: .zero, size: imageSize) + + UIGraphicsBeginImageContextWithOptions(imageSize, false, imageScale) + + defer { UIGraphicsEndImageContext() } + + UIColor.black.setFill() + UIRectFill(contextBounds) + draw(at: .zero) + + guard let imageOverBlack = UIGraphicsGetImageFromCurrentImageContext() else { return self } + tintColor.setFill() + UIRectFill(contextBounds) + + imageOverBlack.draw(at: .zero, blendMode: .multiply, alpha: 1) + draw(at: .zero, blendMode: .destinationIn, alpha: 1) + + guard let finalImage = UIGraphicsGetImageFromCurrentImageContext() else { return self } + + return finalImage + } } diff --git a/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json b/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json new file mode 100644 index 000000000000..ae530e2b5387 --- /dev/null +++ b/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "RouteInfoAnnotationLeftHanded.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png b/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png new file mode 100644 index 0000000000000000000000000000000000000000..d493f2cd057c5e5256d8c48b801ee03fc3a181dc GIT binary patch literal 2391 zcmV-d38?moP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91W&i*H0PeuoiU0rz!AV3xRCodHT-#3+XA~b0VUa~Z zE&`&))*3WkLgI_IKK7}mzLnQDJoyLs;!ACs&}aVu)4nvt3yIK6^aU_djbhTMt>Oih z1q8WY%VoLr{HA+`<7CF&*`2-2H~S^aoSpe*<~zUn{m%Jj_6#{%Y%NE0i^a~3p}*+j z*xV3%NPFF8z3gLWi(NNO>B#2VtYsjO1;~KH+K_TF_mJBpka?nGzKt#W$bIE8#jcJ` zDHAEHRdJ*h8(a2~`^sY)yUM{EE3?KX0`f|4u8q@bYHF(4yLa#5+}zx%ty{O2<>lq= z$jQkm6nYFtE-dYaCmBceSNgQzyI$`mo5$SITKx)2Q0sD5eF|2 zc9F1yXU?42b?n%&&&tZmJ}oIJsSgAKB?L@9E%S+92c zdwXXmCMNnuM@N5bZf?G^u&^N66qP|>2`)8%5VYA2kPUg@Q$nA>kt0V+&z?Q|EybCp zqeqW^a`NQKf|{BdZOax(HtLxH4P&aTtkm}H+gCu6ub~*#Kx3{O8yowJz=BWk4;hVp zgv8i)GXJ+3Agn+`2X5GrTj2ER)0K^ljm>-Z?D^uvi4zqE4<6L$#JoLYmlz{1BE`ob z#ix&m@dpUJp6Ab>|4W0G43g>Jh(R#{1m*x7V$SEMPMz9LaVKK|u^U)vX{ko>F+g!? zcSS|TZi-PI#3UJyVgd+(1Tw>?m_GRwa|$3UFbCk!!D+QO+qP}nG>V(~B(oa2$mRF$ z-Rmal!Dmc(!}MX_jf`eykPIf!sCMDPg+|02$jXb%fe*3)q+l=@n4O)irI<9?(b4fw zWV@7GYycsZH#9VSkARGrqe_F^XwDQQkg91?d*j)&XXbch0K}ByC8)-qAm%wp<%bR( zQUx2s5BLP%;3KUJ(ue)VlJUrer0|8CF_|Iu9H5=g5rcLi3#is28MuIE-4!&c?IIS9 z2pfTaDWi07~nJaaWETPt_ZIgsm`u7j`e*~&LiO5VZifDx*N$$k=OHJEg*gRk(J&d-D~FyR&H8e7JnHw#ddOJtUq zPA#{7eTZ`IjM^OWnWe=`LvtB5*i0HsR$@`E22YHlbW?vbWidR5=4a8o%t|cUrO!$% z3PM?l5kSk!%VGLmACFzR+9NA5Nu2rl`S9A>+LTo71PuRp$WqH@F;s(~WCnFbk~wVqUScSfK|PUO(Uq?yMsY_&9TAGHh%vIJF`LC8 zp_eaTYACWoB^pc0y!5TaDDLRRRj5FVl-L zLLKywY8s=Z!fvBzlD-=Bw(}(NfL-5A%&~jhM^5~tEwh!StmJu94$zAiFSNVd9IW(2<#z%X6Wv@%`5ByVkrX%?4bu!162Co zW_hVHbY)5;#_XZse1+K4AHf2@Lvb?-w`qlx18B@0Z!XVCEckbM2jmOh;?vr$Y zm^}jn1HVUm_L5E@?9QEZiA7>h==SZ~S7{K7VjyzPBIO`$(LFt8QW?bT86F;P>+0&7 zNRNw&oi(WdF?+n0xg?}XlNhsyGS^jNPbhLyc~4|FsgvVNyPY%!c{y{*tCAFem_1(2 zToRz9NQ`4ol*}c^k+HVx3}W_pIdjRY<;xgXJ(HdG8g-dWy})uQ|59E z5VL1!Xy{ijR%l3vo!XWXGarOwk6$vE^gpV^m_79J>vamwo~+Q24m-7@0>td;?CiYm z^x!J=hs0#Tl3vtA|5H$}ykPcF@#Pg_PblKB=PEQ3xlkWu5ZFU?&HePByRRj35-;y- z4$_7%U=PihXApZ@TU*_E^Tas1cMP+{^m1HCj9ypN=s$M9rkBrtCU@*=3%%oMoFlcB z7`9dNJ|FM|I!J+diAPBNsk>mWeE_y5PRd|#fxJOkELYy{{Zh(wJT=MStI}e002ov JPDHLkV1jIPao_*| literal 0 HcmV?d00001 diff --git a/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json b/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json new file mode 100644 index 000000000000..748a6ddd2a74 --- /dev/null +++ b/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "RouteInfoAnnotationRightHanded.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png b/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png new file mode 100644 index 0000000000000000000000000000000000000000..4b9e2e7f0f85e1744af55d0a5c08be05916d8030 GIT binary patch literal 2463 zcmX|Ddpy(YAOC*0p@}j%3vn!yp=2i{zud~Oxn?dUmeX+?p`zR`i&+TZf9=PQn z&z6e1Z~NrDPU4^U3v&nw87eZ=4UK!Vb=YqxMuK>2fS59eBpB-_2up0(oCB9{Jkq&A z&W%0E>1F)oqB#(9p|%`>hm_sNKEa2=m-pW$pvG|hw`8vJt%?pl(X>x%(PH7~oVKRX zz~q)i^vi56yMo!Z(C6)=01C=--MMa6j~{FE>o0JHY&N@OZEdZsuC8uLQ&ThVV~CB7 zO%7S6nsM)FwV|=8sp$~|1A~^Preni=zTjoj&b^y#V}rBeyUz%xR1YsBz8-R1FEol= zEi}KmE0&gge-{5!xEl!2 zz^3pZce1nJ9gqID=x1SJ;raH%httk3E(##)CrtSRgL zV-*f>ejg?#dT($|G*l^-hA;{GmysH;{)VnkJ=&=I;yL;G7dlO&rgND)B_)~DrSxLL zsEP$lMj6h!Ww_4}YSM51wB)^vl7|v&$kx3vSpRPW-QRr=L<|VRKTQQC%{%(qM|_}V zFaD=Q>;mnIdY$9!WOHc6TqxPqo~^`0?K!b3h?!bhSs`weWt5kf$3y!cG+T(vm`B># zvA9$O!(;N)h#d_^|9DV{z8#=KZ#omT_$!*->Pw6f4 z+Wv#hZdyh}f8y5t%%VZFXsyeuxx>Zb@?w)Y5CkvLEgV#@*B&m3+mHT{VM@5gyzr@Zppt(>jmU7bFQh-;8^f{iSzoiF$tx=kw#q ze{?A~PHR>l?zEbW$Kp&>`fD3xh*TIy6YcY0(05%=Y)5kNhd*-p@ZiAGM|b$PM<3pa zNnD4DJL`J2%aV`YWd(?2h4s^trN22!=j%5#bzGD!#@^Q8^=v)#;c#za*VC)I!MtpL z264i}L;7fuc$Qub)*(^7oa^bL{41#;srh>AZj8Rh;1@fH9B8J8$$k;miCOM7(ACwA z8qpZk_lV^=CnAwZOAH2+1x%0RLvZD=7r@q3;T#nZu(VFC&hm}?)x51~Qna}j&WQsx z`_r!5QgIIDKn4YuF72;IpyZ(Cm3KwP3T+{>hDSeJ!P7Dr;s`|TQ@mM}a4S+4r3=H8 z(8p6@Y8&XMhv6egrQSN~iA@5LJ1`WrHs^Sfa$emVzsJjObrVmD-rBfqs+!LiR9|%8 zgR*uwr_w2SH`N~PWp17#F(2hoN9h6tn3QA8%*BJ3eyvbnSXk)jDyS3;6&}x`iW9Nd ztabDuN?#Ey)O<#p$@U0UkgBw=v21xc80thfy*Sx4B1{m0_@aI$*7rgy4 zDA#Wb(@`NeqG{8Bq>1O@Sek#YZC3vN|9APgv~*x$$~-8=N(K}^! z$MCs1>>8{rJw5#jkOMxpUWqV@dpv_7Rg~2OqX||Ar7D1dHwo0RG?*IM$#y+}Msjy^ zQ&_?pOq$B0nt?Lvt)|oh>#<2^x;Q>@Aii|^cxu>pGN=1_;k~Onzp%ul1>LKwt3hG9 z_6Z;{;YpQLp!tleS|rK;;n@xSVAS{T;R?#8aWUWL$0`oqGmdtZ{@K{ac%_n=SR?$1 zB(1z><)cX?Qpf(x^ojOl%)Kjr9vhu}+d}jBdFFiZ3`919pNk*ZYS{euM>N$a(i_%q~gP@2J|D2F%qLo_#A%+33W!lY35{Gcc=N5?Dym=ti}7 zQnvzB6+A|zTyktQCU+z3-Xp&2Nvnju3a#t6_{IMwFy!$_N$#V37Mp8c?^BF4eA}>>YG-RLaqiiToEh=z(5^n)sW;$H|3E6*l;;c z4+H+s>T0QX8shDP3x%5fmPQT+1_qgjQpwd~A}36fzu?adf}9U7mxh>r`<%#T}*3iBsyZ(^?BuGF(gstvJWzmIxFVd?~N? zjL1&(kP|Mw>gGL)(I;w$JQYv6LSV62r_t~BHcO*?R1cXSF)y|t0c0^QBHDrHnfKsX z`UD`!(C?D?^TIrn$2;S9Ea&WV2zz)KD@WC_mZRL6|C2pP+kO?3gFKXZVF55(TgTii zb<3>Qh?N`Q_V=_z=V(CC1hG=xC^yI`jSHY`4TVAHM7KgaMTy#W^PgEPj)l_ zHsR5uP3~q(kl`P%rA}!)IKvUn^rl8_vD7y2xoE;=P=@isE!4M}bDl}N6ot@x#}vcY T?9|?Ge~t(i_PFYkzbE_`06%_> literal 0 HcmV?d00001 From 2725641d9502b2c8ecb0f7db1ff76adcf042e5ea Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Tue, 16 Mar 2021 09:16:20 -0700 Subject: [PATCH 02/16] Rename some variables. --- .../CustomPointAnnotationExample.swift | 78 +++++++++---------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift index 938ebf4f149b..9c9630a25975 100644 --- a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift @@ -4,7 +4,7 @@ import Turf @objc(CustomPointAnnotationExample) -fileprivate enum RouteDurationAnnotationTailPosition: Int { +fileprivate enum AnnotationTailPosition: Int { case left case right } @@ -13,7 +13,7 @@ fileprivate struct DebugFeature { var coordinate: CLLocationCoordinate2D var selected: Bool var sortOrder: Int - var tailPosition: RouteDurationAnnotationTailPosition + var tailPosition: AnnotationTailPosition var label: String var imageName: String } @@ -54,7 +54,7 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { self.updateAnnotationSymbolImages() let features = self.addDebugFeatures() - self.addRouteAnnotationSymbolLayer(features: features) + self.addAnnotationSymbolLayer(features: features) // The below line is used for internal testing purposes only. self.finish() @@ -62,30 +62,29 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { } private func updateAnnotationSymbolImages() { - guard let style = mapView.style, style.getStyleImage(with: "RouteInfoAnnotationLeftHanded") == nil, style.getStyleImage(with: "RouteInfoAnnotationRightHanded") == nil else { return } + guard let style = mapView.style, style.getStyleImage(with: "AnnotationLeftHanded") == nil, style.getStyleImage(with: "AnnotationRightHanded") == nil else { return } - let routeDurationAnnotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) - let routeDurationAnnotationColor = UIColor.white + let annotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) + let annotationColor = UIColor.white // Right-hand pin - if let image = UIImage(named: "RouteInfoAnnotationRightHanded") { - let regularRouteImage = image.tint(routeDurationAnnotationColor) + if let image = UIImage(named: "AnnotationRightHanded") { + let regularAnnotationImage = image.tint(annotationColor) - let lStretchX = ImageStretches(first: Float(32), second: Float(42)) - let stretchX = [lStretchX] + let stretchX = [ImageStretches(first: Float(32), second: Float(42))] let stretchY = [ImageStretches(first: Float(26), second: Float(32))] let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) - style.setStyleImage(image: regularRouteImage, - with: "RouteInfoAnnotationRightHanded", + style.setStyleImage(image: regularAnnotationImage, + with: "AnnotationRightHanded", stretchX: stretchX, stretchY: stretchY, scale: 2.0, imageContent: imageContent) - let selectedRouteImage = image.tint(routeDurationAnnotationSelectedColor) - style.setStyleImage(image: selectedRouteImage, - with: "RouteInfoAnnotationRightHanded-Selected", + let selectedAnnotationImage = image.tint(annotationSelectedColor) + style.setStyleImage(image: selectedAnnotationImage, + with: "AnnotationRightHanded-Selected", stretchX: stretchX, stretchY: stretchY, scale: 2.0, @@ -93,24 +92,23 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { } // Left-hand pin - if let image = UIImage(named: "RouteInfoAnnotationLeftHanded") { - let regularRouteImage = image.tint(routeDurationAnnotationColor) + if let image = UIImage(named: "AnnotationLeftHanded") { + let regularAnnotationImage = image.tint(annotationColor) - let lStretchX = ImageStretches(first: Float(32), second: Float(42)) - let stretchX = [lStretchX] + let stretchX = [ImageStretches(first: Float(32), second: Float(42))] let stretchY = [ImageStretches(first: Float(26), second: Float(32))] let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) - style.setStyleImage(image: regularRouteImage, - with: "RouteInfoAnnotationLeftHanded", + style.setStyleImage(image: regularAnnotationImage, + with: "AnnotationLeftHanded", stretchX: stretchX, stretchY: stretchY, scale: 2.0, imageContent: imageContent) - let selectedRouteImage = image.tint(routeDurationAnnotationSelectedColor) - style.setStyleImage(image: selectedRouteImage, - with: "RouteInfoAnnotationLeftHanded-Selected", + let selectedAnnotationImage = image.tint(annotationSelectedColor) + style.setStyleImage(image: selectedAnnotationImage, + with: "AnnotationLeftHanded-Selected", stretchX: stretchX, stretchY: stretchY, scale: 2.0, @@ -118,15 +116,15 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { } } - static let routeDurationAnnotations = "routeDurationAnnotations" + static let annotations = "annotations" private func addDebugFeatures() -> FeatureCollection { var features = [Feature]() let featureList = [ - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), selected: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway Lefthand Stem", imageName: "RouteInfoAnnotationLeftHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), selected: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John Righthand Stem", imageName: "RouteInfoAnnotationRightHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716908, -74.004016), selected: true, sortOrder: 1, tailPosition: .right, label: "Leonard & Broadway Selected Right", imageName: "RouteInfoAnnotationRightHanded-Selected"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), selected: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold Selected Left", imageName: "RouteInfoAnnotationLeftHanded-Selected") + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), selected: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway Lefthand Stem", imageName: "AnnotationLeftHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), selected: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John Righthand Stem", imageName: "AnnotationRightHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716908, -74.004016), selected: true, sortOrder: 1, tailPosition: .right, label: "Leonard & Broadway Selected Right", imageName: "AnnotationRightHanded-Selected"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), selected: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold Selected Left", imageName: "AnnotationLeftHanded-Selected") ] for (index, feature) in featureList.enumerated() { @@ -141,26 +139,26 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { return FeatureCollection(features: features) } - private func addRouteAnnotationSymbolLayer(features: FeatureCollection) { + private func addAnnotationSymbolLayer(features: FeatureCollection) { guard let style = mapView.style else { return } - if let _ = try? mapView.style.getSource(identifier: CustomPointAnnotationExample.routeDurationAnnotations, type: GeoJSONSource.self).get() { - let _ = mapView.style.updateGeoJSON(for: CustomPointAnnotationExample.routeDurationAnnotations, with: features) + if let _ = try? mapView.style.getSource(identifier: CustomPointAnnotationExample.annotations, type: GeoJSONSource.self).get() { + let _ = mapView.style.updateGeoJSON(for: CustomPointAnnotationExample.annotations, with: features) } else { var dataSource = GeoJSONSource() dataSource.data = .featureCollection(features) - mapView.style.addSource(source: dataSource, identifier: CustomPointAnnotationExample.routeDurationAnnotations) + mapView.style.addSource(source: dataSource, identifier: CustomPointAnnotationExample.annotations) } var shapeLayer: SymbolLayer - if let layer = try? mapView.style.getLayer(with: CustomPointAnnotationExample.routeDurationAnnotations, type: SymbolLayer.self).get() { + if let layer = try? mapView.style.getLayer(with: CustomPointAnnotationExample.annotations, type: SymbolLayer.self).get() { shapeLayer = layer } else { - shapeLayer = SymbolLayer(id: CustomPointAnnotationExample.routeDurationAnnotations) + shapeLayer = SymbolLayer(id: CustomPointAnnotationExample.annotations) } - shapeLayer.source = CustomPointAnnotationExample.routeDurationAnnotations + shapeLayer.source = CustomPointAnnotationExample.annotations shapeLayer.layout?.textField = .expression(Exp(.get) { "text" @@ -223,10 +221,10 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { if let expressionData = expressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, property: "icon-anchor", value: expJSONObject) - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, property: "text-anchor", value: expJSONObject) } @@ -244,11 +242,11 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, property: "icon-offset", value: expJSONObject) - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.routeDurationAnnotations, + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, property: "text-offset", value: expJSONObject) } From 5d922e608348f548d99009248d621267a84e2997 Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Tue, 16 Mar 2021 10:10:03 -0700 Subject: [PATCH 03/16] Get symbol sort order key working. Remove zoom level based font size and comment out symbol offsetting until we get symbol anchoring working reliably. --- .../CustomPointAnnotationExample.swift | 97 +++++++++---------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift index 9c9630a25975..b4db567a8316 100644 --- a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift @@ -67,14 +67,14 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { let annotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) let annotationColor = UIColor.white + let stretchX = [ImageStretches(first: Float(32), second: Float(42))] + let stretchY = [ImageStretches(first: Float(26), second: Float(32))] + let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) + // Right-hand pin if let image = UIImage(named: "AnnotationRightHanded") { let regularAnnotationImage = image.tint(annotationColor) - let stretchX = [ImageStretches(first: Float(32), second: Float(42))] - let stretchY = [ImageStretches(first: Float(26), second: Float(32))] - let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) - style.setStyleImage(image: regularAnnotationImage, with: "AnnotationRightHanded", stretchX: stretchX, @@ -95,10 +95,6 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { if let image = UIImage(named: "AnnotationLeftHanded") { let regularAnnotationImage = image.tint(annotationColor) - let stretchX = [ImageStretches(first: Float(32), second: Float(42))] - let stretchY = [ImageStretches(first: Float(26), second: Float(32))] - let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) - style.setStyleImage(image: regularAnnotationImage, with: "AnnotationLeftHanded", stretchX: stretchX, @@ -131,7 +127,7 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { var featurePoint = Feature(Point(feature.coordinate)) // set the feature attributes which will be used in styling the symbol style layer - featurePoint.properties = ["selected": feature.selected, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, "imageName": feature.imageName, "sortOrder": feature.selected == true ? 1 : -index] + featurePoint.properties = ["selected": feature.selected, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, "imageName": feature.imageName, "sortOrder": feature.selected == true ? index : -index] features.append(featurePoint) } @@ -178,16 +174,17 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { UIColor.black }) - shapeLayer.layout?.textSize = .expression( - Exp(.interpolate) { - Exp(.linear) - Exp(.zoom) - 13 - 16 - 15.5 - 20 - } - ) +// shapeLayer.layout?.textSize = .expression( +// Exp(.interpolate) { +// Exp(.linear) +// Exp(.zoom) +// 13 +// 16 +// 15.5 +// 20 +// } +// ) + shapeLayer.layout?.textSize = .constant(16) shapeLayer.layout?.iconTextFit = .both shapeLayer.layout?.iconAllowOverlap = .constant(true) @@ -195,61 +192,63 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { shapeLayer.layout?.textJustify = .left shapeLayer.layout?.symbolZOrder = .auto shapeLayer.layout?.textFont = .constant(["DIN Pro Medium"]) -// shapeLayer.layout?.iconTextFitPadding = .constant([-4.0, -4.0, -2.0, -4.0]) - shapeLayer.layout?.symbolSortKey = .expression(Exp(.switchCase) { - Exp(.any) { - Exp(.get) { - "selected" - } - } - 1.0 - 0.0 - }) style.addLayer(layer: shapeLayer, layerPosition: nil) - let expressionString = + let symbolSortKeyString = """ - [ - "match", - ["get", "tailPosition"], - ["0"], - "bottom-left", - "bottom-right" - ] + ["get", "sortOrder"] """ - if let expressionData = expressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + if let expressionData = symbolSortKeyString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "icon-anchor", - value: expJSONObject) - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "text-anchor", + property: "symbol-sort-key", value: expJSONObject) } - let offsetExpressionString = + let expressionString = """ [ "match", ["get", "tailPosition"], ["0"], - ["literal", [0.5, -1]], - ["literal", [-0.5, -1]] + "bottom-left", + "bottom-right" ] """ - if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + if let expressionData = expressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "icon-offset", + property: "icon-anchor", value: expJSONObject) - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "text-offset", + property: "text-anchor", value: expJSONObject) } + +// let offsetExpressionString = +// """ +// [ +// "match", +// ["get", "tailPosition"], +// ["0"], +// ["literal", [0.5, -1]], +// ["literal", [-0.5, -1]] +// ] +// """ +// +// if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { +// +// try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, +// property: "icon-offset", +// value: expJSONObject) +// +// try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, +// property: "text-offset", +// value: expJSONObject) +// } } } From 757a48fa2c2ca6dc7c4ca8318b5fa4597dbe8ba8 Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Tue, 16 Mar 2021 11:29:42 -0700 Subject: [PATCH 04/16] Get anchoring working by checking for a numeric value instead of a string value when matching the tailPosition feature attribute. --- .../CustomPointAnnotationExample.swift | 59 ++++++++----------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift index b4db567a8316..16143f9c42c1 100644 --- a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift @@ -174,18 +174,7 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { UIColor.black }) -// shapeLayer.layout?.textSize = .expression( -// Exp(.interpolate) { -// Exp(.linear) -// Exp(.zoom) -// 13 -// 16 -// 15.5 -// 20 -// } -// ) shapeLayer.layout?.textSize = .constant(16) - shapeLayer.layout?.iconTextFit = .both shapeLayer.layout?.iconAllowOverlap = .constant(true) shapeLayer.layout?.textAllowOverlap = .constant(true) @@ -212,9 +201,11 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { [ "match", ["get", "tailPosition"], - ["0"], + [0], "bottom-left", - "bottom-right" + [1], + "bottom-right", + "center" ] """ @@ -228,27 +219,27 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { value: expJSONObject) } -// let offsetExpressionString = -// """ -// [ -// "match", -// ["get", "tailPosition"], -// ["0"], -// ["literal", [0.5, -1]], -// ["literal", [-0.5, -1]] -// ] -// """ -// -// if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { -// -// try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, -// property: "icon-offset", -// value: expJSONObject) -// -// try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, -// property: "text-offset", -// value: expJSONObject) -// } + let offsetExpressionString = + """ + [ + "match", + ["get", "tailPosition"], + [0], + ["literal", [0.5, -1]], + ["literal", [-0.5, -1]] + ] + """ + + if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, + property: "icon-offset", + value: expJSONObject) + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, + property: "text-offset", + value: expJSONObject) + } } } From b096d7d08f2bf2cf8f3d1f21984b154bc0d5140e Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Tue, 16 Mar 2021 15:03:57 -0700 Subject: [PATCH 05/16] Add tap handlers for the annotations. --- .../CustomPointAnnotationExample.swift | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift index 16143f9c42c1..2184074a4934 100644 --- a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift @@ -18,24 +18,25 @@ fileprivate struct DebugFeature { var imageName: String } -public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { +public class CustomPointAnnotationExample: UIViewController, ExampleProtocol, AnnotationInteractionDelegate { internal var mapView: MapView! override public func viewDidLoad() { super.viewDidLoad() + mapView = MapView(with: view.bounds, resourceOptions: resourceOptions()) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + view.addSubview(mapView) + + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector((mapSymbolTap(sender:)))) + mapView.addGestureRecognizer(tapGestureRecognizer) + // Center the map camera over New York City let centerCoordinate = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060) let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 9.0)) - mapView = MapView(frame: view.bounds, mapInitOptions: options) - mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - view.addSubview(mapView) - mapView.cameraManager.setCamera(centerCoordinate: centerCoordinate, - zoom: 15.0) - // Allows the delegate to receive information about map events. mapView.mapboxMap.onNext(.mapLoaded) { [weak self] _ in @@ -52,6 +53,8 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { // Add the annotation to the map. self.mapView.annotations.addAnnotation(customPointAnnotation) + self.mapView.annotationManager.interactionDelegate = self + self.updateAnnotationSymbolImages() let features = self.addDebugFeatures() self.addAnnotationSymbolLayer(features: features) @@ -61,6 +64,30 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { } } + public func didSelectAnnotation(annotation: Annotation) { + print("Selected PointAnnotation at: \(annotation.identifier)") + } + + public func didDeselectAnnotation(annotation: Annotation) { + print("Delected PointAnnotation: \(annotation.identifier)") + } + + @objc private func mapSymbolTap(sender: UITapGestureRecognizer) { + if sender.state == .recognized { + let annotationLayers: Set = [CustomPointAnnotationExample.annotations] + mapView.visibleFeatures(at: sender.location(in: mapView), + styleLayers: annotationLayers, + filter: nil, + completion: { result in + if case .success(let features) = result { + if features.count == 0 { return } + guard let featureText = features[0].properties?["text"] as? String else { return } + print(featureText) + } + }) + } + } + private func updateAnnotationSymbolImages() { guard let style = mapView.style, style.getStyleImage(with: "AnnotationLeftHanded") == nil, style.getStyleImage(with: "AnnotationRightHanded") == nil else { return } From 82ab6f275aa31d8af1b30a5edaa9c776b8f35d5b Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Wed, 17 Mar 2021 09:05:37 -0700 Subject: [PATCH 06/16] Move symbol example to its own new example class. Add centered pin. --- .../Examples.xcodeproj/project.pbxproj | 6 + .../CustomPointAnnotationExample.swift | 263 +------------- Apps/Examples/Examples/Models/Examples.swift | 3 + .../CustomSymbolAnnotationsExample.swift | 339 ++++++++++++++++++ .../AnnotationCentered.png | Bin 0 -> 4850 bytes .../AnnotationCentered.imageset/Contents.json | 12 + 6 files changed, 364 insertions(+), 259 deletions(-) create mode 100644 Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift create mode 100644 Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png create mode 100644 Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json diff --git a/Apps/Examples/Examples.xcodeproj/project.pbxproj b/Apps/Examples/Examples.xcodeproj/project.pbxproj index 15b5a5bdcd46..88a2256375cb 100644 --- a/Apps/Examples/Examples.xcodeproj/project.pbxproj +++ b/Apps/Examples/Examples.xcodeproj/project.pbxproj @@ -61,6 +61,7 @@ CADCF73C258499200065C51B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077C4EED252F7E88007636F1 /* AppDelegate.swift */; }; CADCF743258499570065C51B /* BasicMapExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = CADCF742258499570065C51B /* BasicMapExample.swift */; }; CAF9A9812583E49B007EF9EC /* TestableExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAF9A9802583E49B007EF9EC /* TestableExampleTests.swift */; }; + F46FF17B26025A40007CC0E0 /* CustomSymbolAnnotationsExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -154,6 +155,7 @@ CADCF742258499570065C51B /* BasicMapExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicMapExample.swift; sourceTree = ""; }; CAEF7554257AE02B0003EFF7 /* MapViewExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewExample.swift; sourceTree = ""; }; CAF9A9802583E49B007EF9EC /* TestableExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableExampleTests.swift; sourceTree = ""; }; + F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSymbolAnnotationsExample.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -214,6 +216,9 @@ CA628413262DFD5C00651488 /* OfflineManagerExample.storyboard */, 58A3C0C825C4B93600CAE5F0 /* AnimateGeoJSONLineExample.swift */, 07DBDC91254C94C500F89304 /* AnimateLayerExample.swift */, + F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */, + 07B071D12547CF50007F2865 /* Sample Data */, + CAEF7554257AE02B0003EFF7 /* MapViewExample.swift */, CADCF742258499570065C51B /* BasicMapExample.swift */, CA86E81725BE7C2200E5A1D9 /* BuildingExtrusionsExample.swift */, C64ED3842540A2BE00ADADFB /* CameraAnimationExample.swift */, @@ -504,6 +509,7 @@ CADCF72A2584990E0065C51B /* CustomStyleURLExample.swift in Sources */, CADCF7222584990E0065C51B /* ColorExpressionExample.swift in Sources */, CADCF733258499130065C51B /* Examples.swift in Sources */, + F46FF17B26025A40007CC0E0 /* CustomSymbolAnnotationsExample.swift in Sources */, CADCF743258499570065C51B /* BasicMapExample.swift in Sources */, CADCF7232584990E0065C51B /* UpdatePointAnnotationPositionExample.swift in Sources */, CADCF72C2584990E0065C51B /* PointAnnotationExample.swift in Sources */, diff --git a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift index 2184074a4934..51734e20b5a3 100644 --- a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift @@ -1,24 +1,9 @@ import UIKit import MapboxMaps -import Turf @objc(CustomPointAnnotationExample) -fileprivate enum AnnotationTailPosition: Int { - case left - case right -} - -fileprivate struct DebugFeature { - var coordinate: CLLocationCoordinate2D - var selected: Bool - var sortOrder: Int - var tailPosition: AnnotationTailPosition - var label: String - var imageName: String -} - -public class CustomPointAnnotationExample: UIViewController, ExampleProtocol, AnnotationInteractionDelegate { +public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { internal var mapView: MapView! @@ -29,13 +14,11 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol, An mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(mapView) - let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector((mapSymbolTap(sender:)))) - mapView.addGestureRecognizer(tapGestureRecognizer) - // Center the map camera over New York City let centerCoordinate = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060) - let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, - zoom: 9.0)) + + mapView.cameraManager.setCamera(centerCoordinate: centerCoordinate, + zoom: 9.0) // Allows the delegate to receive information about map events. mapView.mapboxMap.onNext(.mapLoaded) { [weak self] _ in @@ -53,246 +36,8 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol, An // Add the annotation to the map. self.mapView.annotations.addAnnotation(customPointAnnotation) - self.mapView.annotationManager.interactionDelegate = self - - self.updateAnnotationSymbolImages() - let features = self.addDebugFeatures() - self.addAnnotationSymbolLayer(features: features) - // The below line is used for internal testing purposes only. self.finish() } } - - public func didSelectAnnotation(annotation: Annotation) { - print("Selected PointAnnotation at: \(annotation.identifier)") - } - - public func didDeselectAnnotation(annotation: Annotation) { - print("Delected PointAnnotation: \(annotation.identifier)") - } - - @objc private func mapSymbolTap(sender: UITapGestureRecognizer) { - if sender.state == .recognized { - let annotationLayers: Set = [CustomPointAnnotationExample.annotations] - mapView.visibleFeatures(at: sender.location(in: mapView), - styleLayers: annotationLayers, - filter: nil, - completion: { result in - if case .success(let features) = result { - if features.count == 0 { return } - guard let featureText = features[0].properties?["text"] as? String else { return } - print(featureText) - } - }) - } - } - - private func updateAnnotationSymbolImages() { - guard let style = mapView.style, style.getStyleImage(with: "AnnotationLeftHanded") == nil, style.getStyleImage(with: "AnnotationRightHanded") == nil else { return } - - let annotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) - let annotationColor = UIColor.white - - let stretchX = [ImageStretches(first: Float(32), second: Float(42))] - let stretchY = [ImageStretches(first: Float(26), second: Float(32))] - let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) - - // Right-hand pin - if let image = UIImage(named: "AnnotationRightHanded") { - let regularAnnotationImage = image.tint(annotationColor) - - style.setStyleImage(image: regularAnnotationImage, - with: "AnnotationRightHanded", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) - - let selectedAnnotationImage = image.tint(annotationSelectedColor) - style.setStyleImage(image: selectedAnnotationImage, - with: "AnnotationRightHanded-Selected", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) - } - - // Left-hand pin - if let image = UIImage(named: "AnnotationLeftHanded") { - let regularAnnotationImage = image.tint(annotationColor) - - style.setStyleImage(image: regularAnnotationImage, - with: "AnnotationLeftHanded", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) - - let selectedAnnotationImage = image.tint(annotationSelectedColor) - style.setStyleImage(image: selectedAnnotationImage, - with: "AnnotationLeftHanded-Selected", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) - } - } - - static let annotations = "annotations" - - private func addDebugFeatures() -> FeatureCollection { - var features = [Feature]() - let featureList = [ - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), selected: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway Lefthand Stem", imageName: "AnnotationLeftHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), selected: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John Righthand Stem", imageName: "AnnotationRightHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716908, -74.004016), selected: true, sortOrder: 1, tailPosition: .right, label: "Leonard & Broadway Selected Right", imageName: "AnnotationRightHanded-Selected"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), selected: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold Selected Left", imageName: "AnnotationLeftHanded-Selected") - ] - - for (index, feature) in featureList.enumerated() { - var featurePoint = Feature(Point(feature.coordinate)) - - // set the feature attributes which will be used in styling the symbol style layer - featurePoint.properties = ["selected": feature.selected, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, "imageName": feature.imageName, "sortOrder": feature.selected == true ? index : -index] - - features.append(featurePoint) - } - - return FeatureCollection(features: features) - } - - private func addAnnotationSymbolLayer(features: FeatureCollection) { - guard let style = mapView.style else { return } - if let _ = try? mapView.style.getSource(identifier: CustomPointAnnotationExample.annotations, type: GeoJSONSource.self).get() { - let _ = mapView.style.updateGeoJSON(for: CustomPointAnnotationExample.annotations, with: features) - } else { - - var dataSource = GeoJSONSource() - dataSource.data = .featureCollection(features) - mapView.style.addSource(source: dataSource, identifier: CustomPointAnnotationExample.annotations) - } - - var shapeLayer: SymbolLayer - - if let layer = try? mapView.style.getLayer(with: CustomPointAnnotationExample.annotations, type: SymbolLayer.self).get() { - shapeLayer = layer - } else { - shapeLayer = SymbolLayer(id: CustomPointAnnotationExample.annotations) - } - - shapeLayer.source = CustomPointAnnotationExample.annotations - - shapeLayer.layout?.textField = .expression(Exp(.get) { - "text" - }) - - shapeLayer.layout?.iconImage = .expression(Exp(.get) { - "imageName" - }) - - shapeLayer.paint?.textColor = .expression(Exp(.switchCase) { - Exp(.any) { - Exp(.get) { - "selected" - } - } - UIColor.white - UIColor.black - }) - - shapeLayer.layout?.textSize = .constant(16) - shapeLayer.layout?.iconTextFit = .both - shapeLayer.layout?.iconAllowOverlap = .constant(true) - shapeLayer.layout?.textAllowOverlap = .constant(true) - shapeLayer.layout?.textJustify = .left - shapeLayer.layout?.symbolZOrder = .auto - shapeLayer.layout?.textFont = .constant(["DIN Pro Medium"]) - - style.addLayer(layer: shapeLayer, layerPosition: nil) - - let symbolSortKeyString = - """ - ["get", "sortOrder"] - """ - - if let expressionData = symbolSortKeyString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "symbol-sort-key", - value: expJSONObject) - } - - let expressionString = - """ - [ - "match", - ["get", "tailPosition"], - [0], - "bottom-left", - [1], - "bottom-right", - "center" - ] - """ - - if let expressionData = expressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "icon-anchor", - value: expJSONObject) - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "text-anchor", - value: expJSONObject) - } - - let offsetExpressionString = - """ - [ - "match", - ["get", "tailPosition"], - [0], - ["literal", [0.5, -1]], - ["literal", [-0.5, -1]] - ] - """ - - if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "icon-offset", - value: expJSONObject) - - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomPointAnnotationExample.annotations, - property: "text-offset", - value: expJSONObject) - } - } -} - -extension UIImage { - func tint(_ tintColor: UIColor) -> UIImage { - let imageSize = size - let imageScale = scale - let contextBounds = CGRect(origin: .zero, size: imageSize) - - UIGraphicsBeginImageContextWithOptions(imageSize, false, imageScale) - - defer { UIGraphicsEndImageContext() } - - UIColor.black.setFill() - UIRectFill(contextBounds) - draw(at: .zero) - - guard let imageOverBlack = UIGraphicsGetImageFromCurrentImageContext() else { return self } - tintColor.setFill() - UIRectFill(contextBounds) - - imageOverBlack.draw(at: .zero, blendMode: .multiply, alpha: 1) - draw(at: .zero, blendMode: .destinationIn, alpha: 1) - - guard let finalImage = UIGraphicsGetImageFromCurrentImageContext() else { return self } - - return finalImage - } } diff --git a/Apps/Examples/Examples/Models/Examples.swift b/Apps/Examples/Examples/Models/Examples.swift index cd6138dd367e..162e643216de 100644 --- a/Apps/Examples/Examples/Models/Examples.swift +++ b/Apps/Examples/Examples/Models/Examples.swift @@ -39,6 +39,9 @@ public struct Examples { Example(title: "Select an annotation", description: "Select an annotation with a tap gesture.", type: SelectAnnotationExample.self), + Example(title: "Add anchored annotations with a custom map layer.", + description: "Add anchored image annotations to the map with a custom SymbolLayer. Annotations are styled via feature attributes.", + type: CustomSymbolAnnotationsExample.self), Example(title: "Add a GeoJSON data source", description: "Render multiple geometries from GeoJSON data on the map.", type: GeoJSONSourceExample.self), diff --git a/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift new file mode 100644 index 000000000000..d2e6dd7b0336 --- /dev/null +++ b/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -0,0 +1,339 @@ +import UIKit +import MapboxMaps +import Turf + +@objc(CustomSymbolAnnotationsExample) + +fileprivate enum AnnotationTailPosition: Int { + case left + case right + case center +} + +fileprivate struct DebugFeature { + var coordinate: CLLocationCoordinate2D + var selected: Bool + var sortOrder: Int + var tailPosition: AnnotationTailPosition + var label: String + var imageName: String +} + +public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { + + internal var mapView: MapView! + + // Configure a label + public lazy var label: UILabel = { + let label = UILabel(frame: CGRect.zero) + label.translatesAutoresizingMaskIntoConstraints = false + label.backgroundColor = UIColor.systemBlue + label.layer.cornerRadius = 12.0 + label.textColor = UIColor.white + label.textAlignment = .center + label.font = UIFont.boldSystemFont(ofSize: 24.0) + return label + }() + + override public func viewDidLoad() { + super.viewDidLoad() + + mapView = MapView(with: view.bounds, resourceOptions: resourceOptions()) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + view.addSubview(mapView) + + let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector((mapSymbolTap(sender:)))) + mapView.addGestureRecognizer(tapGestureRecognizer) + + // Center the map camera over New York City + let centerCoordinate = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060) + + mapView.cameraManager.setCamera(centerCoordinate: centerCoordinate, + zoom: 15.0) + + // Allows the delegate to receive information about map events. + mapView.on(.mapLoadingFinished) { [weak self] _ in + guard let self = self else { return } + + self.updateAnnotationSymbolImages() + let features = self.addDebugFeatures() + self.addAnnotationSymbolLayer(features: features) + + // The below line is used for internal testing purposes only. + self.finish() + } + + // Add the label on top of the map view controller. + addLabel() + } + + public func addLabel() { + label.text = "Select an annotation" + view.addSubview(label) + + NSLayoutConstraint.activate([ + label.leadingAnchor.constraint(equalTo: view.leadingAnchor), + label.trailingAnchor.constraint(equalTo: view.trailingAnchor), + label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + label.heightAnchor.constraint(equalToConstant: 60.0) + ]) + } + + @objc private func mapSymbolTap(sender: UITapGestureRecognizer) { + if sender.state == .recognized { + let annotationLayers: Set = [CustomSymbolAnnotationsExample.annotations] + mapView.visibleFeatures(at: sender.location(in: mapView), + styleLayers: annotationLayers, + filter: nil, + completion: { result in + if case .success(let features) = result { + if features.count == 0 { return } + guard let featureText = features[0].properties?["text"] as? String else { return } + self.label.text = featureText + } + }) + } + } + + private func updateAnnotationSymbolImages() { + guard let style = mapView.style, style.getStyleImage(with: "AnnotationLeftHanded") == nil, style.getStyleImage(with: "AnnotationRightHanded") == nil else { return } + + let annotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) + let annotationColor = UIColor.white + + // Right-hand pin + if let image = UIImage(named: "AnnotationCentered") { + let stretchX = [ImageStretches(first: Float(20), second: Float(30)), ImageStretches(first: Float(90), second: Float(100))] + let stretchY = [ImageStretches(first: Float(26), second: Float(32))] + let imageContent = ImageContent(left: 20, top: 26, right: 100, bottom: 33) + + let regularAnnotationImage = image.tint(annotationColor) + + style.setStyleImage(image: regularAnnotationImage, + with: "AnnotationCentered", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + + let selectedAnnotationImage = image.tint(annotationSelectedColor) + style.setStyleImage(image: selectedAnnotationImage, + with: "AnnotationCentered-Selected", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + } + + let stretchX = [ImageStretches(first: Float(32), second: Float(42))] + let stretchY = [ImageStretches(first: Float(26), second: Float(32))] + let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) + + // Right-hand pin + if let image = UIImage(named: "AnnotationRightHanded") { + let regularAnnotationImage = image.tint(annotationColor) + + style.setStyleImage(image: regularAnnotationImage, + with: "AnnotationRightHanded", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + + let selectedAnnotationImage = image.tint(annotationSelectedColor) + style.setStyleImage(image: selectedAnnotationImage, + with: "AnnotationRightHanded-Selected", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + } + + // Left-hand pin + if let image = UIImage(named: "AnnotationLeftHanded") { + let regularAnnotationImage = image.tint(annotationColor) + + style.setStyleImage(image: regularAnnotationImage, + with: "AnnotationLeftHanded", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + + let selectedAnnotationImage = image.tint(annotationSelectedColor) + style.setStyleImage(image: selectedAnnotationImage, + with: "AnnotationLeftHanded-Selected", + stretchX: stretchX, + stretchY: stretchY, + scale: 2.0, + imageContent: imageContent) + } + } + + static let annotations = "annotations" + + private func addDebugFeatures() -> FeatureCollection { + var features = [Feature]() + let featureList = [ + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), selected: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway - Lefthand Stem", imageName: "AnnotationLeftHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), selected: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John - Righthand Stem", imageName: "AnnotationRightHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716281, -74.004526), selected: true, sortOrder: 1, tailPosition: .right, label: "Broadway & Worth - Right Selected", imageName: "AnnotationRightHanded-Selected"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), selected: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold - Left Selected", imageName: "AnnotationLeftHanded-Selected"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.7128, -74.0060), selected: true, sortOrder: 2, tailPosition: .center, label: "City Hall - Centered Selected", imageName: "AnnotationCentered-Selected"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.711427, -74.008614), selected: false, sortOrder: 3, tailPosition: .center, label: "Broadway & Vesey - Centered Stem", imageName: "AnnotationCentered") + ] + + for (index, feature) in featureList.enumerated() { + var featurePoint = Feature(Point(feature.coordinate)) + + // set the feature attributes which will be used in styling the symbol style layer + featurePoint.properties = ["selected": feature.selected, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, "imageName": feature.imageName, "sortOrder": feature.selected == true ? index : -index] + + features.append(featurePoint) + } + + return FeatureCollection(features: features) + } + + private func addAnnotationSymbolLayer(features: FeatureCollection) { + guard let style = mapView.style else { return } + if let _ = try? mapView.style.getSource(identifier: CustomSymbolAnnotationsExample.annotations, type: GeoJSONSource.self).get() { + let _ = mapView.style.updateGeoJSON(for: CustomSymbolAnnotationsExample.annotations, with: features) + } else { + + var dataSource = GeoJSONSource() + dataSource.data = .featureCollection(features) + mapView.style.addSource(source: dataSource, identifier: CustomSymbolAnnotationsExample.annotations) + } + + var shapeLayer: SymbolLayer + + if let layer = try? mapView.style.getLayer(with: CustomSymbolAnnotationsExample.annotations, type: SymbolLayer.self).get() { + shapeLayer = layer + } else { + shapeLayer = SymbolLayer(id: CustomSymbolAnnotationsExample.annotations) + } + + shapeLayer.source = CustomSymbolAnnotationsExample.annotations + + shapeLayer.layout?.textField = .expression(Exp(.get) { + "text" + }) + + shapeLayer.layout?.iconImage = .expression(Exp(.get) { + "imageName" + }) + + shapeLayer.paint?.textColor = .expression(Exp(.switchCase) { + Exp(.any) { + Exp(.get) { + "selected" + } + } + UIColor.white + UIColor.black + }) + + shapeLayer.layout?.textSize = .constant(16) + shapeLayer.layout?.iconTextFit = .constant(.both) + shapeLayer.layout?.iconAllowOverlap = .constant(true) + shapeLayer.layout?.textAllowOverlap = .constant(true) + shapeLayer.layout?.textJustify = .constant(.left) + shapeLayer.layout?.symbolZOrder = .constant(.auto) + shapeLayer.layout?.textFont = .constant(["DIN Pro Medium"]) + + style.addLayer(layer: shapeLayer, layerPosition: nil) + + let symbolSortKeyString = + """ + ["get", "sortOrder"] + """ + + if let expressionData = symbolSortKeyString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, + property: "symbol-sort-key", + value: expJSONObject) + } + + let expressionString = + """ + [ + "match", + ["get", "tailPosition"], + [0], + "bottom-left", + [1], + "bottom-right", + [2], + "bottom", + "center" + ] + """ + + if let expressionData = expressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, + property: "icon-anchor", + value: expJSONObject) + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, + property: "text-anchor", + value: expJSONObject) + } + + let offsetExpressionString = + """ + [ + "match", + ["get", "tailPosition"], + [0], + ["literal", [0.5, -1]], + [1], + ["literal", [-0.5, -1]], + [2], + ["literal", [0.0, -1]], + ["literal", [0.0, 0.0]] + ] + """ + + if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, + property: "icon-offset", + value: expJSONObject) + + try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, + property: "text-offset", + value: expJSONObject) + } + } +} + +extension UIImage { + // Produce a copy of the image with tint color applied. + // Useful for deployment to iOS versions prior to 13 where tinting support was added to UIImage natively. + func tint(_ tintColor: UIColor) -> UIImage { + let imageSize = size + let imageScale = scale + let contextBounds = CGRect(origin: .zero, size: imageSize) + + UIGraphicsBeginImageContextWithOptions(imageSize, false, imageScale) + + defer { UIGraphicsEndImageContext() } + + UIColor.black.setFill() + UIRectFill(contextBounds) + draw(at: .zero) + + guard let imageOverBlack = UIGraphicsGetImageFromCurrentImageContext() else { return self } + tintColor.setFill() + UIRectFill(contextBounds) + + imageOverBlack.draw(at: .zero, blendMode: .multiply, alpha: 1) + draw(at: .zero, blendMode: .destinationIn, alpha: 1) + + guard let finalImage = UIGraphicsGetImageFromCurrentImageContext() else { return self } + + return finalImage + } +} diff --git a/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png b/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png new file mode 100644 index 0000000000000000000000000000000000000000..2f35bbc6bce2d6a05869f21e39696473b4e3affa GIT binary patch literal 4850 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 Date: Wed, 17 Mar 2021 09:19:39 -0700 Subject: [PATCH 07/16] Fix typo in comment. --- .../Examples/All Examples/CustomSymbolAnnotationsExample.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift index d2e6dd7b0336..38618ea85d09 100644 --- a/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -101,7 +101,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { let annotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) let annotationColor = UIColor.white - // Right-hand pin + // Centered pin if let image = UIImage(named: "AnnotationCentered") { let stretchX = [ImageStretches(first: Float(20), second: Float(30)), ImageStretches(first: Float(90), second: Float(100))] let stretchY = [ImageStretches(first: Float(26), second: Float(32))] From 552974407323053524484ee36a31cfd2c79c259f Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Wed, 17 Mar 2021 15:28:25 -0700 Subject: [PATCH 08/16] Fix linting error. Respond to review feedback. Change from using selected as an adjective to highlighted to prevent confusion between visibly highlighting some annotations in a different color and selecting them via user interaction. --- .../CustomSymbolAnnotationsExample.swift | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift index 38618ea85d09..cfae51564e6a 100644 --- a/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -2,23 +2,23 @@ import UIKit import MapboxMaps import Turf -@objc(CustomSymbolAnnotationsExample) - -fileprivate enum AnnotationTailPosition: Int { +private enum AnnotationTailPosition: Int { case left case right case center } -fileprivate struct DebugFeature { +private struct DebugFeature { var coordinate: CLLocationCoordinate2D - var selected: Bool + var highlighted: Bool var sortOrder: Int var tailPosition: AnnotationTailPosition var label: String var imageName: String } +@objc(CustomSymbolAnnotationsExample) + public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { internal var mapView: MapView! @@ -98,7 +98,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { private func updateAnnotationSymbolImages() { guard let style = mapView.style, style.getStyleImage(with: "AnnotationLeftHanded") == nil, style.getStyleImage(with: "AnnotationRightHanded") == nil else { return } - let annotationSelectedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) + let annotationHighlightedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) let annotationColor = UIColor.white // Centered pin @@ -116,9 +116,9 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { scale: 2.0, imageContent: imageContent) - let selectedAnnotationImage = image.tint(annotationSelectedColor) - style.setStyleImage(image: selectedAnnotationImage, - with: "AnnotationCentered-Selected", + let highlightedAnnotationImage = image.tint(annotationHighlightedColor) + style.setStyleImage(image: highlightedAnnotationImage, + with: "AnnotationCentered-Highlighted", stretchX: stretchX, stretchY: stretchY, scale: 2.0, @@ -140,9 +140,9 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { scale: 2.0, imageContent: imageContent) - let selectedAnnotationImage = image.tint(annotationSelectedColor) - style.setStyleImage(image: selectedAnnotationImage, - with: "AnnotationRightHanded-Selected", + let highlightedAnnotationImage = image.tint(annotationHighlightedColor) + style.setStyleImage(image: highlightedAnnotationImage, + with: "AnnotationRightHanded-Highlighted", stretchX: stretchX, stretchY: stretchY, scale: 2.0, @@ -160,9 +160,9 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { scale: 2.0, imageContent: imageContent) - let selectedAnnotationImage = image.tint(annotationSelectedColor) - style.setStyleImage(image: selectedAnnotationImage, - with: "AnnotationLeftHanded-Selected", + let highlightedAnnotationImage = image.tint(annotationHighlightedColor) + style.setStyleImage(image: highlightedAnnotationImage, + with: "AnnotationLeftHanded-Highlighted", stretchX: stretchX, stretchY: stretchY, scale: 2.0, @@ -175,19 +175,19 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { private func addDebugFeatures() -> FeatureCollection { var features = [Feature]() let featureList = [ - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), selected: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway - Lefthand Stem", imageName: "AnnotationLeftHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), selected: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John - Righthand Stem", imageName: "AnnotationRightHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716281, -74.004526), selected: true, sortOrder: 1, tailPosition: .right, label: "Broadway & Worth - Right Selected", imageName: "AnnotationRightHanded-Selected"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), selected: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold - Left Selected", imageName: "AnnotationLeftHanded-Selected"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.7128, -74.0060), selected: true, sortOrder: 2, tailPosition: .center, label: "City Hall - Centered Selected", imageName: "AnnotationCentered-Selected"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.711427, -74.008614), selected: false, sortOrder: 3, tailPosition: .center, label: "Broadway & Vesey - Centered Stem", imageName: "AnnotationCentered") + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), highlighted: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway - Lefthand Stem", imageName: "AnnotationLeftHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), highlighted: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John - Righthand Stem", imageName: "AnnotationRightHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716281, -74.004526), highlighted: true, sortOrder: 1, tailPosition: .right, label: "Broadway & Worth - Right Highlighted", imageName: "AnnotationRightHanded-Highlighted"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), highlighted: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold - Left Highlighted", imageName: "AnnotationLeftHanded-Highlighted"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.7128, -74.0060), highlighted: true, sortOrder: 2, tailPosition: .center, label: "City Hall - Centered Highlighted", imageName: "AnnotationCentered-Highlighted"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.711427, -74.008614), highlighted: false, sortOrder: 3, tailPosition: .center, label: "Broadway & Vesey - Centered Stem", imageName: "AnnotationCentered") ] for (index, feature) in featureList.enumerated() { var featurePoint = Feature(Point(feature.coordinate)) // set the feature attributes which will be used in styling the symbol style layer - featurePoint.properties = ["selected": feature.selected, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, "imageName": feature.imageName, "sortOrder": feature.selected == true ? index : -index] + featurePoint.properties = ["highlighted": feature.highlighted, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, "imageName": feature.imageName, "sortOrder": feature.highlighted == true ? index : -index] features.append(featurePoint) } @@ -197,10 +197,10 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { private func addAnnotationSymbolLayer(features: FeatureCollection) { guard let style = mapView.style else { return } - if let _ = try? mapView.style.getSource(identifier: CustomSymbolAnnotationsExample.annotations, type: GeoJSONSource.self).get() { - let _ = mapView.style.updateGeoJSON(for: CustomSymbolAnnotationsExample.annotations, with: features) + let existingDataSource = try? mapView.style.getSource(identifier: CustomSymbolAnnotationsExample.annotations, type: GeoJSONSource.self).get() + if existingDataSource != nil { + _ = mapView.style.updateGeoJSON(for: CustomSymbolAnnotationsExample.annotations, with: features) } else { - var dataSource = GeoJSONSource() dataSource.data = .featureCollection(features) mapView.style.addSource(source: dataSource, identifier: CustomSymbolAnnotationsExample.annotations) @@ -227,7 +227,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { shapeLayer.paint?.textColor = .expression(Exp(.switchCase) { Exp(.any) { Exp(.get) { - "selected" + "highlighted" } } UIColor.white From d76ab1e318ce7897fcc59f7d6e33ae1f60a48582 Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Thu, 18 Mar 2021 09:38:49 -0700 Subject: [PATCH 09/16] Move CustomSymbolAnnotationsExample.swift example to new Examples app project structure. --- Apps/Examples/Examples.xcodeproj/project.pbxproj | 4 ++++ .../CustomSymbolAnnotationsExample.swift | 0 .../AnnotationCentered.png | Bin .../AnnotationCentered.imageset/Contents.json | 0 .../AnnotationLeftHanded.imageset/Contents.json | 0 .../RouteInfoAnnotationLeftHanded.png | Bin .../AnnotationRightHanded.imageset/Contents.json | 0 .../RouteInfoAnnotationRightHanded.png | Bin 8 files changed, 4 insertions(+) rename {Examples => Apps/Examples}/Examples/All Examples/CustomSymbolAnnotationsExample.swift (100%) rename {Examples => Apps/Examples}/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png (100%) rename {Examples => Apps/Examples}/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json (100%) rename {Examples => Apps/Examples}/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json (100%) rename {Examples => Apps/Examples}/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png (100%) rename {Examples => Apps/Examples}/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json (100%) rename {Examples => Apps/Examples}/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png (100%) diff --git a/Apps/Examples/Examples.xcodeproj/project.pbxproj b/Apps/Examples/Examples.xcodeproj/project.pbxproj index 88a2256375cb..c1f493626904 100644 --- a/Apps/Examples/Examples.xcodeproj/project.pbxproj +++ b/Apps/Examples/Examples.xcodeproj/project.pbxproj @@ -227,6 +227,10 @@ 0CC4ECE925B8AD3000F998B8 /* Custom2DPuckExample.swift */, 0C52BA9725AF8C880054ECA8 /* Custom3DPuckExample.swift */, 073475D625AFAE520049B0B8 /* CustomLayerExample.swift */, + CAC195B625AC098A00F69FEA /* CameraUIViewAnimationExample.swift */, + A4AC5DEB2542CB2200995E4C /* CustomStyleURLExample.swift */, + F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */, + C64ED3882540BA0700ADADFB /* PointAnnotationExample.swift */, C64ED3C42540DD6E00ADADFB /* CustomPointAnnotationExample.swift */, A4AC5DEB2542CB2200995E4C /* CustomStyleURLExample.swift */, C69F01EC2543646A001AB49B /* DataDrivenSymbolsExample.swift */, diff --git a/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift similarity index 100% rename from Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift rename to Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift diff --git a/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png b/Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png similarity index 100% rename from Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png rename to Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png diff --git a/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json b/Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json similarity index 100% rename from Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json rename to Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json diff --git a/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json b/Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json similarity index 100% rename from Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json rename to Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json diff --git a/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png b/Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png similarity index 100% rename from Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png rename to Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png diff --git a/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json b/Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json similarity index 100% rename from Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json rename to Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json diff --git a/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png b/Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png similarity index 100% rename from Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png rename to Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png From 88f044bef9986bf07b9bfa5cbad4cce866116db5 Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Tue, 18 May 2021 15:02:35 -0700 Subject: [PATCH 10/16] Update old example and try to adapt to new Maps SDK styling API. --- .../CustomPointAnnotationExample.swift | 11 +- .../CustomSymbolAnnotationsExample.swift | 161 ++++++------------ .../AnnotationCentered.png | Bin 4850 -> 3199 bytes .../RouteInfoAnnotationLeftHanded.png | Bin 2391 -> 2357 bytes .../RouteInfoAnnotationRightHanded.png | Bin 2463 -> 2389 bytes 5 files changed, 61 insertions(+), 111 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift index 51734e20b5a3..6587e4b7f7b6 100644 --- a/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomPointAnnotationExample.swift @@ -10,15 +10,14 @@ public class CustomPointAnnotationExample: UIViewController, ExampleProtocol { override public func viewDidLoad() { super.viewDidLoad() - mapView = MapView(with: view.bounds, resourceOptions: resourceOptions()) - mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - view.addSubview(mapView) - // Center the map camera over New York City let centerCoordinate = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060) + let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, + zoom: 9.0)) - mapView.cameraManager.setCamera(centerCoordinate: centerCoordinate, - zoom: 9.0) + mapView = MapView(frame: view.bounds, mapInitOptions: options) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + view.addSubview(mapView) // Allows the delegate to receive information about map events. mapView.mapboxMap.onNext(.mapLoaded) { [weak self] _ in diff --git a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift index cfae51564e6a..1ff905b386aa 100644 --- a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -38,21 +38,20 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { override public func viewDidLoad() { super.viewDidLoad() - mapView = MapView(with: view.bounds, resourceOptions: resourceOptions()) + // Center the map camera over New York City + let centerCoordinate = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060) + let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, + zoom: 15.0)) + + mapView = MapView(frame: view.bounds, mapInitOptions: options) mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(mapView) let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector((mapSymbolTap(sender:)))) mapView.addGestureRecognizer(tapGestureRecognizer) - // Center the map camera over New York City - let centerCoordinate = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060) - - mapView.cameraManager.setCamera(centerCoordinate: centerCoordinate, - zoom: 15.0) - // Allows the delegate to receive information about map events. - mapView.on(.mapLoadingFinished) { [weak self] _ in + mapView.mapboxMap.onNext(.mapLoaded) { [weak self] _ in guard let self = self else { return } self.updateAnnotationSymbolImages() @@ -82,91 +81,65 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { @objc private func mapSymbolTap(sender: UITapGestureRecognizer) { if sender.state == .recognized { let annotationLayers: Set = [CustomSymbolAnnotationsExample.annotations] - mapView.visibleFeatures(at: sender.location(in: mapView), - styleLayers: annotationLayers, - filter: nil, - completion: { result in - if case .success(let features) = result { - if features.count == 0 { return } - guard let featureText = features[0].properties?["text"] as? String else { return } - self.label.text = featureText - } - }) + + mapView.visibleFeatures(at: sender.location(in: mapView), styleLayers: annotationLayers, filter: nil) { result in + switch result { + case .success(let features): + if features.count > 0 { + guard let featureText = features[0].feature.properties["text"] as? String else { return } + self.label.text = featureText + } + case .failure(let error): + print("An error occurred: \(error.localizedDescription)") + } + } } } private func updateAnnotationSymbolImages() { - guard let style = mapView.style, style.getStyleImage(with: "AnnotationLeftHanded") == nil, style.getStyleImage(with: "AnnotationRightHanded") == nil else { return } + guard let style = mapView.style, style.image(withId: "AnnotationLeftHanded") == nil, style.image(withId: "AnnotationRightHanded") == nil else { return } let annotationHighlightedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) let annotationColor = UIColor.white // Centered pin if let image = UIImage(named: "AnnotationCentered") { - let stretchX = [ImageStretches(first: Float(20), second: Float(30)), ImageStretches(first: Float(90), second: Float(100))] - let stretchY = [ImageStretches(first: Float(26), second: Float(32))] - let imageContent = ImageContent(left: 20, top: 26, right: 100, bottom: 33) + let stretchX = [ImageStretches(first: Float(10), second: Float(15)), ImageStretches(first: Float(45), second: Float(50))] + let stretchY = [ImageStretches(first: Float(13), second: Float(16))] + let imageContent = ImageContent(left: 10, top: 13, right: 50, bottom: 16) let regularAnnotationImage = image.tint(annotationColor) - style.setStyleImage(image: regularAnnotationImage, - with: "AnnotationCentered", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) + try? style.addImage(regularAnnotationImage, id: "AnnotationCentered", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) let highlightedAnnotationImage = image.tint(annotationHighlightedColor) - style.setStyleImage(image: highlightedAnnotationImage, - with: "AnnotationCentered-Highlighted", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) + try? style.addImage(highlightedAnnotationImage, id: "AnnotationCentered-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) } - let stretchX = [ImageStretches(first: Float(32), second: Float(42))] - let stretchY = [ImageStretches(first: Float(26), second: Float(32))] - let imageContent = ImageContent(left: 32, top: 26, right: 47, bottom: 33) + let stretchX = [ImageStretches(first: Float(16), second: Float(21))] + let stretchY = [ImageStretches(first: Float(13), second: Float(16))] + let imageContent = ImageContent(left: 16, top: 13, right: 23, bottom: 16) // Right-hand pin if let image = UIImage(named: "AnnotationRightHanded") { let regularAnnotationImage = image.tint(annotationColor) - style.setStyleImage(image: regularAnnotationImage, - with: "AnnotationRightHanded", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) + try? style.addImage(regularAnnotationImage, id: "AnnotationRightHanded", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) let highlightedAnnotationImage = image.tint(annotationHighlightedColor) - style.setStyleImage(image: highlightedAnnotationImage, - with: "AnnotationRightHanded-Highlighted", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) + + try? style.addImage(highlightedAnnotationImage, id: "AnnotationRightHanded-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) } // Left-hand pin if let image = UIImage(named: "AnnotationLeftHanded") { let regularAnnotationImage = image.tint(annotationColor) - style.setStyleImage(image: regularAnnotationImage, - with: "AnnotationLeftHanded", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) + try? style.addImage(regularAnnotationImage, id: "AnnotationLeftHanded", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) let highlightedAnnotationImage = image.tint(annotationHighlightedColor) - style.setStyleImage(image: highlightedAnnotationImage, - with: "AnnotationLeftHanded-Highlighted", - stretchX: stretchX, - stretchY: stretchY, - scale: 2.0, - imageContent: imageContent) + + try? style.addImage(highlightedAnnotationImage, id: "AnnotationLeftHanded-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) } } @@ -197,19 +170,18 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { private func addAnnotationSymbolLayer(features: FeatureCollection) { guard let style = mapView.style else { return } - let existingDataSource = try? mapView.style.getSource(identifier: CustomSymbolAnnotationsExample.annotations, type: GeoJSONSource.self).get() - if existingDataSource != nil { - _ = mapView.style.updateGeoJSON(for: CustomSymbolAnnotationsExample.annotations, with: features) + if mapView.style.sourceExists(withId: CustomSymbolAnnotationsExample.annotations) { + try? mapView.style.updateGeoJSONSource(withId: CustomSymbolAnnotationsExample.annotations, geoJSON: features) } else { var dataSource = GeoJSONSource() dataSource.data = .featureCollection(features) - mapView.style.addSource(source: dataSource, identifier: CustomSymbolAnnotationsExample.annotations) + try? mapView.style.addSource(dataSource, id: CustomSymbolAnnotationsExample.annotations) } var shapeLayer: SymbolLayer - if let layer = try? mapView.style.getLayer(with: CustomSymbolAnnotationsExample.annotations, type: SymbolLayer.self).get() { - shapeLayer = layer + if mapView.style.layerExists(withId: CustomSymbolAnnotationsExample.annotations) { + shapeLayer = try! mapView.style.layer(withId: CustomSymbolAnnotationsExample.annotations) as SymbolLayer } else { shapeLayer = SymbolLayer(id: CustomSymbolAnnotationsExample.annotations) } @@ -242,7 +214,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { shapeLayer.layout?.symbolZOrder = .constant(.auto) shapeLayer.layout?.textFont = .constant(["DIN Pro Medium"]) - style.addLayer(layer: shapeLayer, layerPosition: nil) + try? style.addLayer(shapeLayer) let symbolSortKeyString = """ @@ -251,35 +223,18 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { if let expressionData = symbolSortKeyString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, - property: "symbol-sort-key", - value: expJSONObject) + try! mapView.mapboxMap.style.setLayerProperties(for: CustomSymbolAnnotationsExample.annotations, properties: ["symbol-sort-key": expJSONObject]) } - let expressionString = - """ - [ - "match", - ["get", "tailPosition"], - [0], - "bottom-left", - [1], - "bottom-right", - [2], - "bottom", - "center" - ] - """ - - if let expressionData = expressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, - property: "icon-anchor", - value: expJSONObject) - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, - property: "text-anchor", - value: expJSONObject) - } + let myExpression = Exp(.match) { + Exp(.get) { "tailPosition" } + [0] + "bottom-left" + [1] + "bottom-right" + "center" + } +// shapeLayer.layout?.iconAnchor = .expression(myExpression) let offsetExpressionString = """ @@ -296,16 +251,12 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { ] """ - if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { - - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, - property: "icon-offset", - value: expJSONObject) - - try! mapView.__map.setStyleLayerPropertyForLayerId(CustomSymbolAnnotationsExample.annotations, - property: "text-offset", - value: expJSONObject) - } +// if let expressionData = offsetExpressionString.data(using: .utf8), let expJSONObject = try? JSONSerialization.jsonObject(with: expressionData, options: []) { +// +// try! mapView.mapboxMap.style.setLayerProperties(for: CustomSymbolAnnotationsExample.annotations, properties: ["icon-offset": expJSONObject]) +// +// try! mapView.mapboxMap.style.setLayerProperties(for: CustomSymbolAnnotationsExample.annotations, properties: ["text-anchor": expJSONObject]) +// } } } diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png b/Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png index 2f35bbc6bce2d6a05869f21e39696473b4e3affa..0127ffac69cb695fbb7639eb35af95e1204dda1e 100644 GIT binary patch literal 3199 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 literal 4850 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 JPDHLkV1jIPao_*| diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png b/Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png index 4b9e2e7f0f85e1744af55d0a5c08be05916d8030..8a3825c8a0a51fe8d4e2ae9549f0c1cc93e10374 100644 GIT binary patch literal 2389 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 T?9|?Ge~t(i_PFYkzbE_`06%_> From a843a9a0ca9e799b1173d4b4e64a9c6a98a2c8ec Mon Sep 17 00:00:00 2001 From: Chris Milack Date: Fri, 16 Jul 2021 12:02:40 -0400 Subject: [PATCH 11/16] Example Text --- Apps/Examples/Examples/Models/Examples.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Apps/Examples/Examples/Models/Examples.swift b/Apps/Examples/Examples/Models/Examples.swift index a24212a026bb..dd168ce9a779 100644 --- a/Apps/Examples/Examples/Models/Examples.swift +++ b/Apps/Examples/Examples/Models/Examples.swift @@ -101,10 +101,10 @@ public struct Examples { Example(title: "Add multiple annotations to a map", description: "Add default and custom annotations to a map.", type: MultiplePointAnnotationsExample.self), + Example(title: "Add anchored annotations with a custom map layer.", + description: "Add anchored image annotations to the map with a custom SymbolLayer. Annotations are styled via feature attributes.", + type: CustomSymbolAnnotationsExample.self), - Example(title: "Add customer annotation images with anchor", - description: "Add customer annotation images with anchor.", - type: CustomSymbolAnnotationsExample.self) ] // Examples that focus on setting, animating, or otherwise changing the map's camera. From 1f14108eef306f21115605d53d249218c1ca550e Mon Sep 17 00:00:00 2001 From: Chris Milack Date: Fri, 16 Jul 2021 13:08:37 -0400 Subject: [PATCH 12/16] linter errors --- .../All Examples/CustomSymbolAnnotationsExample.swift | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift index 05e7fec1b0bd..a21eaac2bb84 100644 --- a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -195,8 +195,6 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { self.annotationManager?.syncAnnotations(annotations) } - - return FeatureCollection(features: features) } @@ -219,7 +217,6 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { shapeLayer.source = CustomSymbolAnnotationsExample.annotations - shapeLayer.textField = .expression(Exp(.get) { "text" }) @@ -272,24 +269,24 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { 0 } Exp(.literal) { - [0.7,-2.0] + [0.7, -2.0] } Exp(.eq) { Exp(.get) { "tailPosition" } 1 } Exp(.literal) { - [-0.7,-2.0] + [-0.7, -2.0] } Exp(.eq) { Exp(.get) { "tailPosition" } 2 } Exp(.literal) { - [-0.2,-2.0] + [-0.2, -2.0] } Exp(.literal) { - [0.0,-2.0] + [0.0, -2.0] } } shapeLayer.textOffset = .expression(offsetExpression) From c43b7043a66e671e12764a4c2f46ca5a8ed8ab89 Mon Sep 17 00:00:00 2001 From: Avi Cieplinski Date: Fri, 16 Jul 2021 10:15:39 -0700 Subject: [PATCH 13/16] Restore symbol annotation tappability. Set feature sort order to get z-ordering correct across annotations. (#547) --- .../CustomSymbolAnnotationsExample.swift | 31 ++++++++++--------- .../Generated/PointAnnotation.swift | 2 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift index a21eaac2bb84..407cae09d185 100644 --- a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -81,21 +81,21 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { } @objc private func mapSymbolTap(sender: UITapGestureRecognizer) { -// if sender.state == .recognized { -// let annotationLayers: Set = [CustomSymbolAnnotationsExample.annotations] -// -// mapView.visibleFeatures(at: sender.location(in: mapView), styleLayers: annotationLayers, filter: nil) { result in -// switch result { -// case .success(let features): -// if features.count > 0 { -// guard let featureText = features[0].feature.properties["text"] as? String else { return } -// self.label.text = featureText -// } -// case .failure(let error): -// print("An error occurred: \(error.localizedDescription)") -// } -// } -// } + if sender.state == .recognized { + let annotationLayers: [String] = [CustomSymbolAnnotationsExample.annotations] + + mapView.mapboxMap.queryRenderedFeatures(at: sender.location(in: mapView), options: RenderedQueryOptions(layerIds: annotationLayers, filter: nil)) { result in + switch result { + case .success(let features): + if features.count > 0 { + guard let featureText = features[0].feature.properties["text"] as? String else { return } + self.label.text = featureText + } + case .failure(let error): + print("An error occurred: \(error.localizedDescription)") + } + } + } } private func updateAnnotationSymbolImages() { @@ -241,6 +241,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { shapeLayer.textAllowOverlap = .constant(true) shapeLayer.textJustify = .constant(.left) shapeLayer.symbolZOrder = .constant(.auto) + shapeLayer.symbolSortKey = .expression(Exp(.get) { "sortOrder" }) shapeLayer.textFont = .constant(["DIN Pro Medium"]) let expression = Exp(.switchCase) { diff --git a/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift b/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift index 517297a2e15c..c99a6b0da283 100644 --- a/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift +++ b/Sources/MapboxMaps/Annotations/Generated/PointAnnotation.swift @@ -311,4 +311,4 @@ public struct PointAnnotation: Annotation { } // End of generated file. -// swiftlint:enable all \ No newline at end of file +// swiftlint:enable all From d51d05028954fe48405551e49e6f0ffbf45cd4f9 Mon Sep 17 00:00:00 2001 From: Chris Milack Date: Fri, 16 Jul 2021 13:19:41 -0400 Subject: [PATCH 14/16] Cleanup and code review --- .../CustomSymbolAnnotationsExample.swift | 30 +++---------------- Apps/Examples/Examples/Models/Examples.swift | 2 +- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift index 407cae09d185..3560d2df7b00 100644 --- a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -18,7 +18,6 @@ private struct DebugFeature { } @objc(CustomSymbolAnnotationsExample) - public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { internal var mapView: MapView! @@ -57,7 +56,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { guard let self = self else { return } self.updateAnnotationSymbolImages() - let features = self.addDebugFeatures() + let features = self.addFeatures()() self.addAnnotationSymbolLayer(features: features) // The below line is used for internal testing purposes only. @@ -100,7 +99,6 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { private func updateAnnotationSymbolImages() { let style = mapView.mapboxMap.style -// guard let style = mapView.mapboxMap.style, style.image(withId: "AnnotationLeftHanded") == nil, style.image(withId: "AnnotationRightHanded") == nil else { return } let annotationHighlightedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) let annotationColor = UIColor.white @@ -132,13 +130,6 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { let highlightedAnnotationImage = image.tint(annotationHighlightedColor) try? style.addImage(highlightedAnnotationImage, id: "AnnotationRightHanded-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) - -// try? style.addImage(UIImage.solid()!, id: "AnnotationRightHanded-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) -// -// try? style.addImage(UIImage.solid()!, -// id: "AnnotationRightHanded-Highlighted", -// sdf: false, -// content: imageContent) } // Left-hand pin @@ -155,7 +146,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { static let annotations = "annotations" - private func addDebugFeatures() -> FeatureCollection { + private func addFeatures() -> FeatureCollection { var features = [Turf.Feature]() @@ -168,17 +159,11 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { DebugFeature(coordinate: CLLocationCoordinate2DMake(40.711427, -74.008614), highlighted: false, sortOrder: 3, tailPosition: .center, label: "Broadway & Vesey - Centered Stem", imageName: "AnnotationCentered") ] - self.annotationManager = mapView.annotations.makeCircleAnnotationManager() - var annotations = [CircleAnnotation]() - for (index, feature) in featureList.enumerated() { - // var featurePoint = Feature(Point(feature.coordinate)) - let point = Turf.Point(feature.coordinate) -// let feature = Turf.Feature(geometry: point) var pointFeature = Feature(geometry: .point(point)) - // set the feature attributes which will be used in styling the symbol style layer + // Set the feature attributes which will be used in styling the symbol style layer. pointFeature.properties = ["highlighted": feature.highlighted, "tailPosition": feature.tailPosition.rawValue, "text": feature.label, @@ -186,13 +171,6 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { "sortOrder": feature.highlighted == true ? index : -index] features.append(pointFeature) - - var annotation = CircleAnnotation(centerCoordinate: feature.coordinate) - annotation.circleColor = .init(color: .red) - annotation.circleRadius = 10 - annotations.append(annotation) - - self.annotationManager?.syncAnnotations(annotations) } return FeatureCollection(features: features) @@ -292,7 +270,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { } shapeLayer.textOffset = .expression(offsetExpression) - try! mapView.mapboxMap.style.addLayer(shapeLayer) + try? mapView.mapboxMap.style.addLayer(shapeLayer) } } diff --git a/Apps/Examples/Examples/Models/Examples.swift b/Apps/Examples/Examples/Models/Examples.swift index dd168ce9a779..51ffa265404c 100644 --- a/Apps/Examples/Examples/Models/Examples.swift +++ b/Apps/Examples/Examples/Models/Examples.swift @@ -102,7 +102,7 @@ public struct Examples { description: "Add default and custom annotations to a map.", type: MultiplePointAnnotationsExample.self), Example(title: "Add anchored annotations with a custom map layer.", - description: "Add anchored image annotations to the map with a custom SymbolLayer. Annotations are styled via feature attributes.", + description: "Add custom annotations to the map with a SymbolLayer. The custom annotations are styled based on feature attributes and are anchored to specific points on the map.", type: CustomSymbolAnnotationsExample.self), ] From 74e31c65cce9f577df95694e254414fbb24f27da Mon Sep 17 00:00:00 2001 From: Chris Milack Date: Fri, 16 Jul 2021 13:25:24 -0400 Subject: [PATCH 15/16] More cleanup --- .../All Examples/CustomSymbolAnnotationsExample.swift | 2 +- .../Examples/Controllers/ExampleTableViewController.swift | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift index 3560d2df7b00..863db2a9566b 100644 --- a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift @@ -56,7 +56,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { guard let self = self else { return } self.updateAnnotationSymbolImages() - let features = self.addFeatures()() + let features = self.addFeatures() self.addAnnotationSymbolLayer(features: features) // The below line is used for internal testing purposes only. diff --git a/Apps/Examples/Examples/Controllers/ExampleTableViewController.swift b/Apps/Examples/Examples/Controllers/ExampleTableViewController.swift index caa5a892fca5..62c665c10d07 100644 --- a/Apps/Examples/Examples/Controllers/ExampleTableViewController.swift +++ b/Apps/Examples/Examples/Controllers/ExampleTableViewController.swift @@ -20,11 +20,6 @@ public class ExampleTableViewController: UITableViewController { searchBar.delegate = self - DispatchQueue.main.async { - let vc = CustomSymbolAnnotationsExample() - self.navigationController?.pushViewController(vc, animated: false) - } - tableView.register(UITableViewCell.self, forCellReuseIdentifier: "reuseIdentifier") } } From c4b4c558c8ba863b3e1234ba849148fd55bc064a Mon Sep 17 00:00:00 2001 From: Chris Milack Date: Fri, 16 Jul 2021 14:19:35 -0400 Subject: [PATCH 16/16] Removed refrences to annotations --- .../Examples.xcodeproj/project.pbxproj | 16 +-- ...wift => CustomAnchoredSymbolExample.swift} | 123 ++++++++++-------- .../AnnotationCentered.png | Bin .../Contents.json | 0 .../Contents.json | 0 .../RouteInfoAnnotationLeftHanded.png | Bin .../Contents.json | 0 .../RouteInfoAnnotationRightHanded.png | Bin Apps/Examples/Examples/Models/Examples.swift | 2 +- 9 files changed, 76 insertions(+), 65 deletions(-) rename Apps/Examples/Examples/All Examples/{CustomSymbolAnnotationsExample.swift => CustomAnchoredSymbolExample.swift} (71%) rename Apps/Examples/Examples/Assets.xcassets/{AnnotationCentered.imageset => ImageCalloutCentered.imageset}/AnnotationCentered.png (100%) rename Apps/Examples/Examples/Assets.xcassets/{AnnotationCentered.imageset => ImageCalloutCentered.imageset}/Contents.json (100%) rename Apps/Examples/Examples/Assets.xcassets/{AnnotationLeftHanded.imageset => ImageCalloutLeftHanded.imageset}/Contents.json (100%) rename Apps/Examples/Examples/Assets.xcassets/{AnnotationLeftHanded.imageset => ImageCalloutLeftHanded.imageset}/RouteInfoAnnotationLeftHanded.png (100%) rename Apps/Examples/Examples/Assets.xcassets/{AnnotationRightHanded.imageset => ImageCalloutRightHanded.imageset}/Contents.json (100%) rename Apps/Examples/Examples/Assets.xcassets/{AnnotationRightHanded.imageset => ImageCalloutRightHanded.imageset}/RouteInfoAnnotationRightHanded.png (100%) diff --git a/Apps/Examples/Examples.xcodeproj/project.pbxproj b/Apps/Examples/Examples.xcodeproj/project.pbxproj index 730e3e2f038b..7e736c00f4c1 100644 --- a/Apps/Examples/Examples.xcodeproj/project.pbxproj +++ b/Apps/Examples/Examples.xcodeproj/project.pbxproj @@ -74,7 +74,7 @@ CADCF73C258499200065C51B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 077C4EED252F7E88007636F1 /* AppDelegate.swift */; }; CADCF743258499570065C51B /* BasicMapExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = CADCF742258499570065C51B /* BasicMapExample.swift */; }; CAF9A9812583E49B007EF9EC /* TestableExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAF9A9802583E49B007EF9EC /* TestableExampleTests.swift */; }; - F46FF17B26025A40007CC0E0 /* CustomSymbolAnnotationsExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */; }; + F46FF17B26025A40007CC0E0 /* CustomAnchoredSymbolExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = F46FF17A26025A3F007CC0E0 /* CustomAnchoredSymbolExample.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -181,7 +181,7 @@ CAC195B625AC098A00F69FEA /* CameraAnimatorsExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraAnimatorsExample.swift; sourceTree = ""; }; CADCF742258499570065C51B /* BasicMapExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicMapExample.swift; sourceTree = ""; }; CAF9A9802583E49B007EF9EC /* TestableExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableExampleTests.swift; sourceTree = ""; }; - F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomSymbolAnnotationsExample.swift; sourceTree = ""; }; + F46FF17A26025A3F007CC0E0 /* CustomAnchoredSymbolExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomAnchoredSymbolExample.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -242,21 +242,15 @@ 58A3C0C825C4B93600CAE5F0 /* AnimateGeoJSONLineExample.swift */, 17B480592684FB2300CF0D5E /* AnimateImageLayerExample.swift */, 07DBDC91254C94C500F89304 /* AnimateLayerExample.swift */, - F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */, - 07B071D12547CF50007F2865 /* Sample Data */, - CAEF7554257AE02B0003EFF7 /* MapViewExample.swift */, CADCF742258499570065C51B /* BasicMapExample.swift */, CA86E81725BE7C2200E5A1D9 /* BuildingExtrusionsExample.swift */, C64ED3842540A2BE00ADADFB /* CameraAnimationExample.swift */, - CAC195B625AC098A00F69FEA /* CameraAnimatorsExample.swift */, 0CE3D3BE25818626000585A2 /* ColorExpressionExample.swift */, 0CC4ECE925B8AD3000F998B8 /* Custom2DPuckExample.swift */, 0C52BA9725AF8C880054ECA8 /* Custom3DPuckExample.swift */, 073475D625AFAE520049B0B8 /* CustomLayerExample.swift */, - CAC195B625AC098A00F69FEA /* CameraUIViewAnimationExample.swift */, - A4AC5DEB2542CB2200995E4C /* CustomStyleURLExample.swift */, - F46FF17A26025A3F007CC0E0 /* CustomSymbolAnnotationsExample.swift */, - C64ED3882540BA0700ADADFB /* PointAnnotationExample.swift */, + CAC195B625AC098A00F69FEA /* CameraAnimatorsExample.swift */, + F46FF17A26025A3F007CC0E0 /* CustomAnchoredSymbolExample.swift */, C64ED3C42540DD6E00ADADFB /* CustomPointAnnotationExample.swift */, A4AC5DEB2542CB2200995E4C /* CustomStyleURLExample.swift */, C69F01EC2543646A001AB49B /* DataDrivenSymbolsExample.swift */, @@ -573,7 +567,7 @@ CADCF7222584990E0065C51B /* ColorExpressionExample.swift in Sources */, 17E28C5C2672A1160033DF0F /* SymbolClusteringExample.swift in Sources */, CADCF733258499130065C51B /* Examples.swift in Sources */, - F46FF17B26025A40007CC0E0 /* CustomSymbolAnnotationsExample.swift in Sources */, + F46FF17B26025A40007CC0E0 /* CustomAnchoredSymbolExample.swift in Sources */, CADCF743258499570065C51B /* BasicMapExample.swift in Sources */, CADCF7232584990E0065C51B /* UpdatePointAnnotationPositionExample.swift in Sources */, CADCF72C2584990E0065C51B /* PointAnnotationExample.swift in Sources */, diff --git a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift b/Apps/Examples/Examples/All Examples/CustomAnchoredSymbolExample.swift similarity index 71% rename from Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift rename to Apps/Examples/Examples/All Examples/CustomAnchoredSymbolExample.swift index 863db2a9566b..f2293e986c4c 100644 --- a/Apps/Examples/Examples/All Examples/CustomSymbolAnnotationsExample.swift +++ b/Apps/Examples/Examples/All Examples/CustomAnchoredSymbolExample.swift @@ -2,7 +2,7 @@ import UIKit import MapboxMaps import Turf -private enum AnnotationTailPosition: Int { +private enum SymbolTailPosition: Int { case left case right case center @@ -12,18 +12,17 @@ private struct DebugFeature { var coordinate: CLLocationCoordinate2D var highlighted: Bool var sortOrder: Int - var tailPosition: AnnotationTailPosition + var tailPosition: SymbolTailPosition var label: String var imageName: String } -@objc(CustomSymbolAnnotationsExample) -public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { +@objc(CustomAnchoredSymbolExample) +public class CustomAnchoredSymbolExample: UIViewController, ExampleProtocol { + static let symbols = "custom_symbols" internal var mapView: MapView! - internal var annotationManager: CircleAnnotationManager? - // Configure a label public lazy var label: UILabel = { let label = UILabel(frame: CGRect.zero) @@ -55,9 +54,9 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { mapView.mapboxMap.onNext(.mapLoaded) { [weak self] _ in guard let self = self else { return } - self.updateAnnotationSymbolImages() + self.updateSymbolImages() let features = self.addFeatures() - self.addAnnotationSymbolLayer(features: features) + self.addSymbolLayer(features: features) // The below line is used for internal testing purposes only. self.finish() @@ -68,7 +67,7 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { } public func addLabel() { - label.text = "Select an annotation" + label.text = "Select A Marker" view.addSubview(label) NSLayoutConstraint.activate([ @@ -81,9 +80,10 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { @objc private func mapSymbolTap(sender: UITapGestureRecognizer) { if sender.state == .recognized { - let annotationLayers: [String] = [CustomSymbolAnnotationsExample.annotations] + let layers: [String] = [CustomAnchoredSymbolExample.symbols] - mapView.mapboxMap.queryRenderedFeatures(at: sender.location(in: mapView), options: RenderedQueryOptions(layerIds: annotationLayers, filter: nil)) { result in + mapView.mapboxMap.queryRenderedFeatures(at: sender.location(in: mapView), + options: RenderedQueryOptions(layerIds: layers, filter: nil)) { result in switch result { case .success(let features): if features.count > 0 { @@ -97,24 +97,31 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { } } - private func updateAnnotationSymbolImages() { + private func updateSymbolImages() { let style = mapView.mapboxMap.style - let annotationHighlightedColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) - let annotationColor = UIColor.white + let regularTintColor = UIColor.white + let highlightTintColor = UIColor(hue: 0.831372549, saturation: 0.72, brightness: 0.59, alpha: 1.0) // Centered pin - if let image = UIImage(named: "AnnotationCentered") { + if let image = UIImage(named: "ImageCalloutCentered") { let stretchX = [ImageStretches(first: Float(10), second: Float(15)), ImageStretches(first: Float(45), second: Float(50))] let stretchY = [ImageStretches(first: Float(13), second: Float(16))] let imageContent = ImageContent(left: 10, top: 13, right: 50, bottom: 16) - let regularAnnotationImage = image.tint(annotationColor) - - try? style.addImage(regularAnnotationImage, id: "AnnotationCentered", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) - - let highlightedAnnotationImage = image.tint(annotationHighlightedColor) - try? style.addImage(highlightedAnnotationImage, id: "AnnotationCentered-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) + try? style.addImage(image.tint(regularTintColor), + id: "imageCentered", + sdf: false, + stretchX: stretchX, + stretchY: stretchY, + content: imageContent) + + try? style.addImage(image.tint(highlightTintColor), + id: "imageCentered-Highlighted", + sdf: false, + stretchX: stretchX, + stretchY: stretchY, + content: imageContent) } let stretchX = [ImageStretches(first: Float(16), second: Float(21))] @@ -122,41 +129,51 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { let imageContent = ImageContent(left: 16, top: 13, right: 23, bottom: 16) // Right-hand pin - if let image = UIImage(named: "AnnotationRightHanded") { - let regularAnnotationImage = image.tint(annotationColor) - - try? style.addImage(regularAnnotationImage, id: "AnnotationRightHanded", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) - - let highlightedAnnotationImage = image.tint(annotationHighlightedColor) - - try? style.addImage(highlightedAnnotationImage, id: "AnnotationRightHanded-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) + if let image = UIImage(named: "ImageCalloutRightHanded") { + try? style.addImage(image.tint(regularTintColor), + id: "imageRightHanded", + sdf: false, + stretchX: stretchX, + stretchY: stretchY, + content: imageContent) + + try? style.addImage(image.tint(highlightTintColor), + id: "imageRightHanded-Highlighted", + sdf: false, + stretchX: stretchX, + stretchY: stretchY, + content: imageContent) } // Left-hand pin - if let image = UIImage(named: "AnnotationLeftHanded") { - let regularAnnotationImage = image.tint(annotationColor) - - try? style.addImage(regularAnnotationImage, id: "AnnotationLeftHanded", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) - - let highlightedAnnotationImage = image.tint(annotationHighlightedColor) - - try? style.addImage(highlightedAnnotationImage, id: "AnnotationLeftHanded-Highlighted", sdf: false, stretchX: stretchX, stretchY: stretchY, content: imageContent) + if let image = UIImage(named: "ImageCalloutLeftHanded") { + try? style.addImage(image.tint(regularTintColor), + id: "imageLeftHanded", + sdf: false, + stretchX: stretchX, + stretchY: stretchY, + content: imageContent) + + try? style.addImage(image.tint(highlightTintColor), + id: "imageLeftHanded-Highlighted", + sdf: false, + stretchX: stretchX, + stretchY: stretchY, + content: imageContent) } } - static let annotations = "annotations" - private func addFeatures() -> FeatureCollection { var features = [Turf.Feature]() let featureList = [ - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), highlighted: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway - Lefthand Stem", imageName: "AnnotationLeftHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), highlighted: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John - Righthand Stem", imageName: "AnnotationRightHanded"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716281, -74.004526), highlighted: true, sortOrder: 1, tailPosition: .right, label: "Broadway & Worth - Right Highlighted", imageName: "AnnotationRightHanded-Highlighted"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), highlighted: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold - Left Highlighted", imageName: "AnnotationLeftHanded-Highlighted"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.7128, -74.0060), highlighted: true, sortOrder: 2, tailPosition: .center, label: "City Hall - Centered Highlighted", imageName: "AnnotationCentered-Highlighted"), - DebugFeature(coordinate: CLLocationCoordinate2DMake(40.711427, -74.008614), highlighted: false, sortOrder: 3, tailPosition: .center, label: "Broadway & Vesey - Centered Stem", imageName: "AnnotationCentered") + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.714203, -74.006314), highlighted: false, sortOrder: 0, tailPosition: .left, label: "Chambers & Broadway - Lefthand Stem", imageName: "imageLeftHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.707918, -74.006008), highlighted: false, sortOrder: 0, tailPosition: .right, label: "Cliff & John - Righthand Stem", imageName: "imageRightHanded"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.716281, -74.004526), highlighted: true, sortOrder: 1, tailPosition: .right, label: "Broadway & Worth - Right Highlighted", imageName: "imageRightHanded-Highlighted"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.710194, -74.004248), highlighted: true, sortOrder: 1, tailPosition: .left, label: "Spruce & Gold - Left Highlighted", imageName: "imageLeftHanded-Highlighted"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.7128, -74.0060), highlighted: true, sortOrder: 2, tailPosition: .center, label: "City Hall - Centered Highlighted", imageName: "imageCentered-Highlighted"), + DebugFeature(coordinate: CLLocationCoordinate2DMake(40.711427, -74.008614), highlighted: false, sortOrder: 3, tailPosition: .center, label: "Broadway & Vesey - Centered Stem", imageName: "imageCentered") ] for (index, feature) in featureList.enumerated() { @@ -176,24 +193,24 @@ public class CustomSymbolAnnotationsExample: UIViewController, ExampleProtocol { return FeatureCollection(features: features) } - private func addAnnotationSymbolLayer(features: FeatureCollection) { - if mapView.mapboxMap.style.sourceExists(withId: CustomSymbolAnnotationsExample.annotations) { - try? mapView.mapboxMap.style.updateGeoJSONSource(withId: CustomSymbolAnnotationsExample.annotations, geoJSON: features) + private func addSymbolLayer(features: FeatureCollection) { + if mapView.mapboxMap.style.sourceExists(withId: CustomAnchoredSymbolExample.symbols) { + try? mapView.mapboxMap.style.updateGeoJSONSource(withId: CustomAnchoredSymbolExample.symbols, geoJSON: features) } else { var dataSource = GeoJSONSource() dataSource.data = .featureCollection(features) - try? mapView.mapboxMap.style.addSource(dataSource, id: CustomSymbolAnnotationsExample.annotations) + try? mapView.mapboxMap.style.addSource(dataSource, id: CustomAnchoredSymbolExample.symbols) } var shapeLayer: SymbolLayer - if mapView.mapboxMap.style.layerExists(withId: CustomSymbolAnnotationsExample.annotations) { - shapeLayer = try! mapView.mapboxMap.style.layer(withId: CustomSymbolAnnotationsExample.annotations) as SymbolLayer + if mapView.mapboxMap.style.layerExists(withId: CustomAnchoredSymbolExample.symbols) { + shapeLayer = try! mapView.mapboxMap.style.layer(withId: CustomAnchoredSymbolExample.symbols) as SymbolLayer } else { - shapeLayer = SymbolLayer(id: CustomSymbolAnnotationsExample.annotations) + shapeLayer = SymbolLayer(id: CustomAnchoredSymbolExample.symbols) } - shapeLayer.source = CustomSymbolAnnotationsExample.annotations + shapeLayer.source = CustomAnchoredSymbolExample.symbols shapeLayer.textField = .expression(Exp(.get) { "text" diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png b/Apps/Examples/Examples/Assets.xcassets/ImageCalloutCentered.imageset/AnnotationCentered.png similarity index 100% rename from Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/AnnotationCentered.png rename to Apps/Examples/Examples/Assets.xcassets/ImageCalloutCentered.imageset/AnnotationCentered.png diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json b/Apps/Examples/Examples/Assets.xcassets/ImageCalloutCentered.imageset/Contents.json similarity index 100% rename from Apps/Examples/Examples/Assets.xcassets/AnnotationCentered.imageset/Contents.json rename to Apps/Examples/Examples/Assets.xcassets/ImageCalloutCentered.imageset/Contents.json diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json b/Apps/Examples/Examples/Assets.xcassets/ImageCalloutLeftHanded.imageset/Contents.json similarity index 100% rename from Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/Contents.json rename to Apps/Examples/Examples/Assets.xcassets/ImageCalloutLeftHanded.imageset/Contents.json diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png b/Apps/Examples/Examples/Assets.xcassets/ImageCalloutLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png similarity index 100% rename from Apps/Examples/Examples/Assets.xcassets/AnnotationLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png rename to Apps/Examples/Examples/Assets.xcassets/ImageCalloutLeftHanded.imageset/RouteInfoAnnotationLeftHanded.png diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json b/Apps/Examples/Examples/Assets.xcassets/ImageCalloutRightHanded.imageset/Contents.json similarity index 100% rename from Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/Contents.json rename to Apps/Examples/Examples/Assets.xcassets/ImageCalloutRightHanded.imageset/Contents.json diff --git a/Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png b/Apps/Examples/Examples/Assets.xcassets/ImageCalloutRightHanded.imageset/RouteInfoAnnotationRightHanded.png similarity index 100% rename from Apps/Examples/Examples/Assets.xcassets/AnnotationRightHanded.imageset/RouteInfoAnnotationRightHanded.png rename to Apps/Examples/Examples/Assets.xcassets/ImageCalloutRightHanded.imageset/RouteInfoAnnotationRightHanded.png diff --git a/Apps/Examples/Examples/Models/Examples.swift b/Apps/Examples/Examples/Models/Examples.swift index 51ffa265404c..b3efde74b831 100644 --- a/Apps/Examples/Examples/Models/Examples.swift +++ b/Apps/Examples/Examples/Models/Examples.swift @@ -103,7 +103,7 @@ public struct Examples { type: MultiplePointAnnotationsExample.self), Example(title: "Add anchored annotations with a custom map layer.", description: "Add custom annotations to the map with a SymbolLayer. The custom annotations are styled based on feature attributes and are anchored to specific points on the map.", - type: CustomSymbolAnnotationsExample.self), + type: CustomAnchoredSymbolExample.self), ]