From 6163e94478429edf90fce45e6a5cd59ed22dfa55 Mon Sep 17 00:00:00 2001 From: Bart Louwers Date: Mon, 15 Jul 2024 18:10:00 +0200 Subject: [PATCH] iOS Documentation: Add example adding multiple images (#2607) --- MODULE.bazel | 14 +++ .../MapLibre.docc/MultipleImagesExample.md | 99 ++++++++++++++++++ .../16px-nps-restrooms.png | Bin 0 -> 587 bytes .../48px-nps-restrooms .png | Bin 0 -> 3114 bytes .../nps-restrooms.imageset/Contents.json | 23 ++++ .../nps-restrooms.imageset/nps-restrooms.png | Bin 0 -> 1138 bytes .../16px-nps-trailhead.png | Bin 0 -> 564 bytes .../48x-nps-trailhead.png | Bin 0 -> 3404 bytes .../nps-trailhead.imageset/Contents.json | 23 ++++ .../nps-trailhead.imageset/nps-trailhead.png | Bin 0 -> 1199 bytes .../nps-viewpoint.imageset/Contents.json | 23 ++++ .../nps-viewpoint.imageset/Viewpoint-16.png | Bin 0 -> 657 bytes .../nps-viewpoint.imageset/Viewpoint-32.png | Bin 0 -> 1402 bytes .../nps-viewpoint.imageset/Viewpoint-48.png | Bin 0 -> 2205 bytes platform/ios/app-swift/BUILD.bazel | 3 + .../Sources/MapLibreNavigationView.swift | 3 + .../Sources/MultipleImagesExample.swift | 72 +++++++++++++ 17 files changed, 260 insertions(+) create mode 100644 platform/ios/MapLibre.docc/MultipleImagesExample.md create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/16px-nps-restrooms.png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/48px-nps-restrooms .png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/Contents.json create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/nps-restrooms.png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/16px-nps-trailhead.png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/48x-nps-trailhead.png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/Contents.json create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/nps-trailhead.png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Contents.json create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-16.png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-32.png create mode 100644 platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-48.png create mode 100644 platform/ios/app-swift/Sources/MultipleImagesExample.swift diff --git a/MODULE.bazel b/MODULE.bazel index 2b24366ac..728b691bc 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -22,3 +22,17 @@ use_repo(pnpm, "pnpm") provisioning_profile_repository = use_extension("@build_bazel_rules_apple//apple:apple.bzl", "provisioning_profile_repository_extension") provisioning_profile_repository.setup() + +http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") + +# This file was created as follows: +# Download shapefile from NPS +# https://public-nps.opendata.arcgis.com/datasets/a40e2faa953b4c5cb7fe10004dc3008e_0/explore?location=0.213550%2C-12.488250%2C2.00 +# ogr2ogr -f GeoJSON pois.json -t_srs EPSG:4326 nps-pois.shp +# tippecanoe -o pois-nps.mbtiles pois.json +http_file( + name = "pois_nps_mbtiles", + downloaded_file_path = "pois-nps.mbtiles", + sha256 = "6a218702a5a60bb6358494217cac2836a087355ac092f6b01f089d8b1b2842ca", + url = "https://maplibre-native.s3.eu-central-1.amazonaws.com/ios-swift-example-app-resources/pois-nps.mbtiles", +) diff --git a/platform/ios/MapLibre.docc/MultipleImagesExample.md b/platform/ios/MapLibre.docc/MultipleImagesExample.md new file mode 100644 index 000000000..584fab205 --- /dev/null +++ b/platform/ios/MapLibre.docc/MultipleImagesExample.md @@ -0,0 +1,99 @@ +# Adding Multiple Images + +Adding images to the map and assigning them to POI types + +> This example uses UIKit. + +This example uses POIs in national parks and adds them to the map with data and icons provided by the National Park Service. Both the data and the icons are in the public domain. + +## Preparation + +We've done all the work for you and generated [`pois-nps.mbtiles`](https://maplibre-native.s3.eu-central-1.amazonaws.com/ios-swift-example-app-resources/pois-nps.mbtiles), which you can download directly. +You can skip the rest of this section unless you're curious how we built the MBTiles from the source data. + +- Data, Shapefile download: [https://public-nps.opendata.arcgis.com/datasets/a40e2faa953b4c5cb7fe10004dc3008e_0/](https://public-nps.opendata.arcgis.com/datasets/a40e2faa953b4c5cb7fe10004dc3008e_0/) +- Icons: [https://www.nps.gov/subjects/gisandmapping/map-symbols-patterns-for-nps-maps.htm](https://www.nps.gov/subjects/gisandmapping/map-symbols-patterns-for-nps-maps.htm) + +Convert the data first to GeoJSON format with [`ogr2ogr`](https://gdal.org/programs/ogr2ogr.html) and then to GeoJSON format using [tippecanoe](https://github.com/felt/tippecanoe). + +``` +ogr2ogr -f GeoJSON pois.json -t_srs EPSG:4326 nps-pois.shp +tippecanoe -o pois-nps.mbtiles pois.json +``` + +The resulting `.mbtiles` file can be hosted with a tile server such as [Martin](https://martin.maplibre.org/) or embedded in the app bundle as a resource. Since the file is quite small in this case we will use that last option in this example. Martin comes with a [`mbtiles` binary](https://maplibre.org/martin/mbtiles-meta.html) that allows us to inspect what the MBTiles file contains from the command line. + +``` +mbtiles meta-all pois-nps.mbtiles +``` + +The important thing to note is that there is a `pois` layer whose features include a `POITYPE` attribute. While we could add icons for all kinds of `POITYPE` values included in the dataset, we will only add icons for restrooms, trailheads and viewpoints, and leave the rest as an exercise to the reader. + +The icons need to be extracted with a tool like [Inkscape](https://inkscape.org/) because the National Park Service includes all icons in a big vector file. This is outside the scope of this example. + +## Adding Icons on Style Load + +The `.mbtiles` file needs to be added to the assets of the app. When the style loads we can add a ``MLNVectorTileSource`` with as URL `mbtiles://\(Bundle.main.bundlePath)/pois-nps.mbtiles"`. + +The images need to be added to an imageset so they can be loaded as an `UIImage` and added to the style with ``MLNStyle/setImage:forName:`` as is shown below in the example. Note that you should set ``MLNVectorStyleLayer/sourceLayerIdentifier`` to match the layer name in the MBTiles file. Lastly a [`match` expression](https://maplibre.org/maplibre-style-spec/expressions/#match) is used to select the correct image based on `POITYPE` attribute present in the feature. + + + +```swift +class MultipleImagesExample: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + + mapView = MLNMapView(frame: view.bounds, styleURL: AMERICANA_STYLE) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.tintColor = .darkGray + + let glacierPoint = CLLocationCoordinate2D(latitude: 37.72836462778902, longitude: -119.57352616838511) + mapView.setCenter(glacierPoint, animated: false) + mapView.zoomLevel = 12 + + mapView.delegate = self + view.addSubview(mapView) + } + + // Wait until the style is loaded before modifying the map style. + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + let source = MLNVectorTileSource(identifier: "pois-nps", configurationURL: URL(string: "mbtiles://\(Bundle.main.bundlePath)/pois-nps.mbtiles")!) + + style.addSource(source) + + let imagesToAdd = [ + ["nps-restrooms", "restrooms"], + ["nps-trailhead", "trailhead"], + ["nps-viewpoint", "viewpoint"], + ] + + for imageInfo in imagesToAdd { + if let imageName = imageInfo.first, let imageKey = imageInfo.last { + if let image = UIImage(named: imageName) { + style.setImage(image, forName: imageKey) + } else { + print("Failed to load \(imageName)") + return + } + } + } + + let imageLayer = MLNSymbolStyleLayer(identifier: "npc-poi-images", source: source) + imageLayer.sourceLayerIdentifier = "pois" + imageLayer.iconImageName = NSExpression(mglJSONObject: [ + "match", ["get", "POITYPE"], + "Restroom", "restrooms", + "Trailhead", "trailhead", + "Viewpoint", "viewpoint", + "", + ]) + + style.addLayer(imageLayer) + } +} +``` + +![](MultipleImagesExample.png) \ No newline at end of file diff --git a/platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/16px-nps-restrooms.png b/platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/16px-nps-restrooms.png new file mode 100644 index 0000000000000000000000000000000000000000..2b297a7febb06ca3c8248320f1b8f94be2a0a7d1 GIT binary patch literal 587 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 literal 0 HcmV?d00001 diff --git a/platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/Contents.json b/platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/Contents.json new file mode 100644 index 000000000..b7f7730fc --- /dev/null +++ b/platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "16px-nps-restrooms.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "nps-restrooms.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "48px-nps-restrooms .png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/nps-restrooms.png b/platform/ios/app-swift/Assets.xcassets/nps-restrooms.imageset/nps-restrooms.png new file mode 100644 index 0000000000000000000000000000000000000000..cba577d51801b4524206b7ac1a52029515837c28 GIT binary patch literal 1138 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+081LO4opAc7|0%K!iB?Scs zTf2~;pa5?lZ4C`od3m6?m6>^NR<@Fyl8U^dhqH@@s;aq(iI%#$vb=nNpTCNVii?v| zOH-4w0to16YDR^Hr>Cac+t@0}$sIX-6*}A7=gpaO^27-fL&Ghb zH|J(&Pwb!IXlH-u;KA3gU-$R+e*5wRNjjt~_`4tdEDMk)D29O3JHOubw}9 z9vK#{rmSphX|-+3)<1v#SX)>m#KsjB6lkk!eE9I;?3pu_<>mU?Iz{;fYD&uQ-oEqo z@{W&*2?-49?e4j7;exTg!H(_QFPuNGqM*2T%^Dw1ueO%ft5>d^KX=Z}*`=a9f-n~l}EjoSb^oDiozkU7M z*VA+7&YkPmuiv|OZ}P-RW=6)JKY#xB@89p=zXSdJ_UzjI<;$1lOP9@=H7hGUBgj8M zPfPpl+qaV@Ow7y9u{1MpX=*-x?3lZYtA>i|&!0b!9y#*<-Mhz+A78t6ZP9{-FJHX) z_3KwhTifA7hi=`xnUj^p-h4nA7=^MWL4LsutQD7@JXoj6bm*5&%H7qw))&8Izxgjf zV9uvMmz+-~o#zHBWK8mQcabaNQqTr+*h@TpUD+Qoa|r1Qm>1VK1EuplT^vI!PA4ZM zq$H&sWQ@3ZLsG)RBK2tjQ>9)Wn;fg9jl;z0jsBeTnJiP;>h^pp(h6W*mGw$0p>5eT zvl-VeUcKxdmXMHgT~VN-%2Bl9w?tE;zE7ikOa2RahCqP~36>|U?JaGNqAl(&O-~l{ zELP;|NlJ43v*QQLil!qfr4t-BC33kqW_d_;%%3;0GuClh;x^Te`IBca?+A6Qs$;z2 z+1l6E7$GVmI^97gHY$uSP#}^qEFd$2m6u(-qls&V`D)WEyxCd2uVr2jxSl+*;?*|Fp7=P)K#RlR&8v5gVHdJ*T(?hD3hJ6= zQt4$f!?5&LiNMmpn0U$FIZr;QR5waih@MFinA7TiFS^4qBE>B4CtIK)8(SggNlS}{ zDO-4$87jLEnr*K6@BtVbswJ)wB`Jv|saDBFsX&Us$iUD-*T7iUz#_!Z!pg+d%Fs;P nz`)ADK=gTe~DWM4f*oEIX literal 0 HcmV?d00001 diff --git a/platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/16px-nps-trailhead.png b/platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/16px-nps-trailhead.png new file mode 100644 index 0000000000000000000000000000000000000000..33ba54307b41f6358c6c53e32aa954c291a1f4ca GIT binary patch literal 564 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 YQ3^!GGFMTcFTXf?+D2L*G#sM-0|5LoZU6uP literal 0 HcmV?d00001 diff --git a/platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/Contents.json b/platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/Contents.json new file mode 100644 index 000000000..48c8b9bf8 --- /dev/null +++ b/platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "16px-nps-trailhead.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "nps-trailhead.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "48x-nps-trailhead.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/nps-trailhead.png b/platform/ios/app-swift/Assets.xcassets/nps-trailhead.imageset/nps-trailhead.png new file mode 100644 index 0000000000000000000000000000000000000000..7914f703385e5b879febfddc7093aa6de4b24134 GIT binary patch literal 1199 zcmV;g1W@~lP)K~z|Uy_f$_6K5R9-$%ck3DCH*NszgIL!n(p8_FFnD7cMHU1nVT zLCxIa_-S*@ECF1|lKrqKF>W*B{)%lGV4~R~Y52lSg#;$+C?BUqoDTN`i0vM zm7~X(!ga9EPtWswKF@Qn`+R%u2msJ(wcC_3`PWrdRUee^*zqE^Q2t3KlM~}U&-~n6 z$7Cq<00(eD-qg5{aXFp*|0S_#lt0(ekv3>FZ=y=0X}dKrP|!ghw}-!arH3CH9F)8_ zl}hpN9X|XgYIg7bC6P!-KEUmE^Lz9L-k{O)291{Q@9mR(M)&y(e37bDRYH=aHD+vvV{ z5lzj_xZHCEw+04KS67GAt*r$CY{&y1w;Pd21hccV_;>-hfCx0vvaL#xw6 zCX;O)0OMeUG1WjL91f%F+?SY{nL!{Bz!zuFA{vcuC4gNR({uxd2ZxYIB!sniEC##H zzS>rVf+76SbG2}QbUF=}(Lebgy2Lb_MO(v5;rBY#RYz&?4?fCh}pAZU$1ig>r zU^E)nJb&FXeE--nD3v5!PA85WJqpI*0MGM+UaQl=Y&N5>w-?v?`f;tV9{_Nstqtv+ z9hexOKy^(`;Q%EiB{+Wa1dg9P0RZSee?g?5o}R{y-+slZk3NL$z76;9-Gj^J1kdxB zdh`g}U)YY~;^M*qmJ7>>V;zsh;PrZ8wpd`cSn$c2PX*n;&6_Y9*N#81!7^NwSTy^v z6;O`V6VS)`^15F#fXn4XCY`;22!asSnN_MH3&6pYrvfAcu*}kf-fC$PAXt_aCFY`V z9ETdy+7%!fAoooV9y$b_P6q&(pPPe!a#Ca)iA3=9$rDsoR&EYJDwV>B$0N)snu4{y zUYI+U<-tbcF9{&GBUV&Y;N@MrP*-mi^vk;==k>z$YX1030$>?d7*jM203r|M<_7@y zeB9=GKy)KEGynkfdOg%?HGphGnwpwg0`TT{uDn)Ti^b3SfZvaBI1J9q<^2W_0YoB^cruyHYeW=f-H12B@ z=@bfukP~vb90Z802iEC;K(>L&R3)mH%x3euI=y~P!+MGWNs>6-`ms;}xkB&V3zFQ1 z&pvNMbxk#rsU(`3nxRlC);u$l&fxN;@1|k3S`}~X-|rdmj7a{qDpca}IR8~wSEfp< zJxBmRZFzZdvb6LYqtSHg6^*7eH_0|zo<4h)`D1i+bawXd&dFfV_AhPyQ`apHnoR%z N002ovPDHLkV1ncqK8*kX literal 0 HcmV?d00001 diff --git a/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Contents.json b/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Contents.json new file mode 100644 index 000000000..f3b8a8ddd --- /dev/null +++ b/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Viewpoint-16.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Viewpoint-32.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Viewpoint-48.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-16.png b/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-16.png new file mode 100644 index 0000000000000000000000000000000000000000..a627fb21e58dcd98e134b1c1c5c72f66779041a8 GIT binary patch literal 657 zcmV;C0&e|@P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10v<_3 zK~y-6m6Fj2Go(6-kSS;AeZ^1rz9Y4xtg;zBo5)Q-d@xW%c zT==D>MD#TqZ(*y!0XTomKPVnvMe&WEasm)#*QFhd1(nXQADj)`@2LD z7yJ6~HWF@~0m~j52N4*C0mA?c!vMg+e!p%Zn4Srs%h(08*^HBVJzfN#!{Kz|{_HGF zCex8mIB3gp9LC&kobK$z)LlQq(I~!dZ)4!fRXmuRgYZo_K44!~s})-939Q9pc%Mqb z>+@kVmBz5mhIf&uG9kem_JaM&ZwE;l)FBQjenDqIux4Q?uUJn4!Xfz7?>d$I}85tV# r-@Y^c%3v_)6pmvgieh6U5uf=3{w6zK($7do00000NkvXXu0mjfsuwAZ literal 0 HcmV?d00001 diff --git a/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-32.png b/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-32.png new file mode 100644 index 0000000000000000000000000000000000000000..8c252c7bdc5ca634dd4569d5fbc678dca506396d GIT binary patch literal 1402 zcmV-=1%>*FP)~HzyJUM8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H11qVq) zK~z|Uy_a1~R7Vtmzg>mZ-2etL@+X+=E{YIaLn{?38eb|Zm=;BCRA3h{sjCDWT zbH15-bIuu!5CT(}DLP=f|KX_UsCV>wy*IB>2KxJ5%{OoU+SA>=x%JMS7K}5D(b?9_ zAw^MyyD~B|;j7qT6H}4jk)C5a>v;9_4T>!(<6Wr<;QWkTmbm^_)vD}5MEwh>bleE zq^Pivb*XC@85tR00H@Q*sc%lI<2`$e37s)R9XB;Lk(9WMcaHoW zJ5UrwwbL8)tWHfOGdr80pdfc#y9eNOI`Q-K!?rz-(9lq}<>pddS*5P~`}?zg;|4aS zr!!^B6t@C<1h6zQk+}GH?Co}zzqge8_wNG`J~JF^Ru(C%R-x1BJPQ0mfbQ;YN{Wi9 zudgR0B!t{;HWtLiVKC_F>gpnL&KxXOE6FR9nK03cJ65`_3eqiy!1o8EW6Jl_1@TK|zTh3PDRxP-2?mSBp z7SY&ngSv|sSo`5R0Pc2luxn=l332h1m6jq)lE)X|7J%NM$Kh~LQoNVD9UT;xl<@iC z!)n&+?d_$k^dJl4-=(OqP)$_h2Cy(80h8H`%jIIrN1N&I?V}5L`YBxAA z!0}_{EJ;{Ip3O$*g9qaSpwVc^uvh@F+wBzZDFPrkIGB^)o+7`X;F-qc@#Du_z48-! zgJFCC0NzjefPjDi08Up_aJITyg-f?&P*qdItl6_v`@B!KkiTOG z_IA5Eo;7a>TAEt*2KooEZOvhLcvxMZG-(n$ckSX- zMFm=|d#*hKm^yW;nh^mS8yYD+aA1s`-k^8er&e(&E>9pbGXJe+fkA=Hj*RqV`!k{_ zii_Bom`k2M&9W>O@#(&OqOY&-r81xpLddc#=EubRh$$>AD$8R1UmvHkEQ>6Q)oBh7 zkJJbuFo%anO`SIFP*ikuoZet~?a%Y3rsk`1PxqGFcKfZr0kLgoM~Q8Rr2qf`07*qo IM6N<$f^IpY(f|Me literal 0 HcmV?d00001 diff --git a/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-48.png b/platform/ios/app-swift/Assets.xcassets/nps-viewpoint.imageset/Viewpoint-48.png new file mode 100644 index 0000000000000000000000000000000000000000..d60baa7f81054310a0c48567b89fa272dbe62ac2 GIT binary patch literal 2205 zcmV;O2x9k%P)(PN&^50 zAy5Sb{8Fn_8~3O0BTY?BgyT5!s)6G;($v^U($n@5txDBCZQ8UMgb+aI=QlyCR2wU< zTycw|p`jtS*l~p`mo5{nO4UAf>eTVn*zptovLXI#{JcD(3{VhdfPzFWc#C{nQQ;Q5j?mQD zNR$DJ|4KB0%13pL4Kk@zDymmFj>E!v^U=}KVJDA>jKp8l{)WkuCyTQ0$X}2~YnD2oZLtjtWry|)Byt*tn7>J;kh>jnE4 zP2lA56X00RPL{SW9dfyxr`yrqj%9K2$jUqnjvH>naUAxg?G@}_6oLN!etdQItex!l z%a>zuY%EW=q^KA%QBk;AQ^TvPx^@j0%gY7DAd0|OXa8>Z5~?*C?E2_KJDrCQA0m0( zdTdKg#X$dnQ(GCI9Dvnoec>4Rlk_>kaU4#bIAJTxWHNl3br_>ZkG9DwuU2CF)~)Ei zf8VJcZy#?gS-KQ!*R6w){YWr@%a<;pt+mxw-o0lJbUGaXz-%@nD>D;$UmS7TtG>Rz zSiT|wD^{(-xN+lzh9R85v1c}}sF-NPEsF;LG&VHgPh0+oy1F`t?d1OcShadJ;+Dn3 z%gals`=`*WHG&RPl~*fCROH)aPWZ0~P1D3`wUT4`1w^mb*ba2h{uW2akmAB3!n*Oe z9i-6`!6RUpV?gQof11&60E&>*d z1=p*pV7zC<6u&8WBRm{3nGBwup78VY!_IBn?SiK~C`3ocV105Df`WtH9<&`snnM4+ zew`S?!|kTS>^H*6^{OhHPN%VxOxNj&UacXiDJi76x!G;g#1(=xS|ZV_HROK{cN~&y zZf?eJV`Ckz-(KF{IQMlalu9Ll;UzODI0(MJzAiiL(W6J`F_~a8nP4*Y*q*z)yV2c! zA10IOv8>1TTyXM)ZH0Rl!CIZ`DfGqXIZij9!GQtfWM|{xp+f+GkQpJkSXKs_Ww@wC39y&b!D?0mt{#KYy* zH`1!{GFFurh075L4GTj{ON-O`u&^-Ov)tbwA0Ipbh8~_W3`2u{Nb{zV*=%-S^caD_ zhK(EW&H3}_>+9py`S|!?rBW#tMMq(MQZhnjgt+cO5eU}m@LU9( z!D6xCepeT~yuGn&`wo0tQNh!BnMa9WtxkACQ*rqUq9WhM`*HE`peP*4KZ^AI`*|nK zn(At-PfSE?bPP(0ioprk2V6lgfunhOXlrdnXJ;oq-1TQjBof5GzYHa%|A0Oyh^Jp) zUyp66saQCF0ge|O!{FecsKB2J$J#rB=S`ifyiRR{J0K+L|;kgp%^?IAmweP>jw$!b--__;R z&ZtqN5VQE#*!00>D5fc1C+iQQvGj9BNWasAKKt=|~(J-FI-Iyd0sghw|!X8w^+&86hkPp*isrbai$Ttx{#T zQ_q?nLfYHf9O|<}LnQa}99tWWQc3FT>IL}@(rAh3tHobTnuO?>7&}>SZ!b1)+T`%; zPkDGCX+tv378N2u5rE|h3DD}a!UGUH0)!CqpWC+`-b5Vu_!F1y`uh4vPfw3vzit@; z0GJ*U;&5&s$<0OO)k>%Be0+Q`X3Q8-zTNf@&FZylc`~cjimfRrc<|tXyWH>~@Si%BCx0z8lz08^4saX?mSxRSE626my?a-*L5iZVa@8tZS*cW_;KXrc z=jLG2=0~ zK`xj3YE|lcS1!BfQv-M2eLBPCiKohR+I00000NkvXXu0mjfOf^K3 literal 0 HcmV?d00001 diff --git a/platform/ios/app-swift/BUILD.bazel b/platform/ios/app-swift/BUILD.bazel index dcd0a60af..495a52b2c 100644 --- a/platform/ios/app-swift/BUILD.bazel +++ b/platform/ios/app-swift/BUILD.bazel @@ -31,6 +31,9 @@ ios_application( infoplists = [":Info.plist"], minimum_os_version = "16.0", provisioning_profile = "xcode_profile", + resources = [ + "@pois_nps_mbtiles//file", + ], visibility = ["@rules_xcodeproj//xcodeproj:generated"], deps = [":Sources"], ) diff --git a/platform/ios/app-swift/Sources/MapLibreNavigationView.swift b/platform/ios/app-swift/Sources/MapLibreNavigationView.swift index fbfccd4e9..9b98c14e0 100644 --- a/platform/ios/app-swift/Sources/MapLibreNavigationView.swift +++ b/platform/ios/app-swift/Sources/MapLibreNavigationView.swift @@ -45,6 +45,9 @@ struct MapLibreNavigationView: View { NavigationLink("POIAlongRouteExample") { POIAlongRouteExampleUIViewControllerRepresentable() } + NavigationLink("MultipleImagesExample") { + MultipleImagesExampleUIViewControllerRepresentable().edgesIgnoringSafeArea(.all) + } } } } diff --git a/platform/ios/app-swift/Sources/MultipleImagesExample.swift b/platform/ios/app-swift/Sources/MultipleImagesExample.swift new file mode 100644 index 000000000..bc077e367 --- /dev/null +++ b/platform/ios/app-swift/Sources/MultipleImagesExample.swift @@ -0,0 +1,72 @@ + +import MapLibre +import SwiftUI +import UIKit + +// #-example-code(MultipleImagesExample) +class MultipleImagesExample: UIViewController, MLNMapViewDelegate { + var mapView: MLNMapView! + + override func viewDidLoad() { + super.viewDidLoad() + + mapView = MLNMapView(frame: view.bounds, styleURL: AMERICANA_STYLE) + mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + mapView.tintColor = .darkGray + + let glacierPoint = CLLocationCoordinate2D(latitude: 37.72836462778902, longitude: -119.57352616838511) + mapView.setCenter(glacierPoint, animated: false) + mapView.zoomLevel = 12 + + mapView.delegate = self + view.addSubview(mapView) + } + + // Wait until the style is loaded before modifying the map style. + func mapView(_: MLNMapView, didFinishLoading style: MLNStyle) { + let source = MLNVectorTileSource(identifier: "pois-nps", configurationURL: URL(string: "mbtiles://\(Bundle.main.bundlePath)/pois-nps.mbtiles")!) + + style.addSource(source) + + let imagesToAdd = [ + ["nps-restrooms", "restrooms"], + ["nps-trailhead", "trailhead"], + ["nps-viewpoint", "viewpoint"], + ] + + for imageInfo in imagesToAdd { + if let imageName = imageInfo.first, let imageKey = imageInfo.last { + if let image = UIImage(named: imageName) { + style.setImage(image, forName: imageKey) + } else { + print("Failed to load \(imageName)") + return + } + } + } + + let imageLayer = MLNSymbolStyleLayer(identifier: "npc-poi-images", source: source) + imageLayer.sourceLayerIdentifier = "pois" + imageLayer.iconImageName = NSExpression(mglJSONObject: [ + "match", ["get", "POITYPE"], + "Restroom", "restrooms", + "Trailhead", "trailhead", + "Viewpoint", "viewpoint", + "", + ]) + + style.addLayer(imageLayer) + } +} + +// #-end-example-code + +struct MultipleImagesExampleUIViewControllerRepresentable: UIViewControllerRepresentable { + typealias UIViewControllerType = MultipleImagesExample + + func makeUIViewController(context _: Context) -> MultipleImagesExample { + MultipleImagesExample() + } + + func updateUIViewController(_: MultipleImagesExample, context _: Context) {} +}