A Self-Contained Map With Multiple, Aggregated, Custom Markers
This package was specifically designed to offer SwiftUI apps the opportunity to have a much more involved map experience than that provided by default.
It also allows a "drop in" high-functionality map for UIKit projects.
This is the online documentation for the library
SwiftUI has a very weak implementation of Apple's MapKit mapping framework. It really only supports display of simple maps, with singular, low-interactivity overlays. BigJuJuMap implements a map view with multiple, highly-interactive markers.
Additionally, Apple's clustering algorithm leaves a bit to be desired, so BigJuJuMap implements a simpler, faster one.
This also provides a "turnkey" solution to UIKit implementations, for a very common mapping workflow.
Why MapKit?
Even though MapKit's functionality is more limited than some commercial offerings, it works fine (Apple Maps has come a long way, since its rather chaotic genesis). For the most part, it's an excellent, natively-implemented mapping package.
The main reason to use it, however, is that, as a native framework, it is unencumbered by licensing and support issues. It will not prevent you from updating to the latest operating systems, and there will never be questions about intellectual property or third-party interference.
BigJuJuMap is a very "lightweight" wrapper for Apple Maps. Its entire functionality is contained in just one source file. Internally, it works exactly like any native app, and is easy to understand and modify, with excellent documentation support: both online, and as embedded DocC. It should be easy to fork and modify.
The implementation is provided as a static framework, instantiating a custom UIViewController subclass (BigJuJuMapViewController).
The library is designed to be installed as a Swift Package Manager (SPM) package. The package is available from GitHub. A direct SPM URI is git@github.com:LittleGreenViper/BigJuJuMap.git.
Add the package to your project, and include it into your target.
Whenever you use it, you will need to import it, thusly:
import BigJuJuMap
You use it by instantiating BigJuJuMapViewController, and providing it with a dataset (the dataset must conform to the BigJuJuMapLocationProtocol protocol, and must be a class; not a struct).
You can also, optionally, provide the view controller with alternate marker graphic assets (the default is a simple map marker).
Additionally, you can choose to have the number of aggregated data points displayed in aggregate (multi) markers.
There are two test harness targets provided with the library: A UIKit target, and a SwiftUI target. They show simple implementations of BigJuJuMap, in practice.
They are visually identical, presenting a single screen, filled with a map, and displaying a number of markers. At the bottom of the screen, are two segmented switches. The top switch selects which type of marker to display (default, custom simple, or custom complex), and the bottom switch selects between three different location datasets.
The following images show the types of markers that can be selected by the app.
The marker selection is made by changing the top segmented switch. Changing the marker does not affect the displayed region.
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
The following images show the test datasets we use.
The dataset selection is made by selecting one of the values in the bottom segmented switch. The map is changed to display the new dataset.
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
NOTE: Because the total area for this dataset is so large, Apple Maps limits the size of the region. If you scroll West, a bit, you'll see American Samoa.
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
When we select a marker, a popover appears, above or below the marker.
In the case of aggregate markers, a scrolling table of values is shown.
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
For a single marker, only one value is shown.
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
Note the custom font and color.
When we select one of the values in a popover, the popover is dismissed, and this alert is shown:
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
NOTE: In the test harness app, we display an alert, but anything can happen, when a marker is selected.
You can change the color and font used for the popover display, by providing values for the BigJuJuMapLocationProtocol.textColor, or the BigJuJuMapLocationProtocol.textFont properties of each data item.
It is possible to have every item display its own font and color (but that might be a bit much; you're probably better off applying the same font and color to them all).
![]() |
![]() |
|---|---|
| Light Mode | Dark Mode |
NOTE: The "USA" dataset also supports "sticky popovers."
Usually, when the user selects a value in the popover, the popover closes. It is possible to change this, so the popover stays open, after the user selects the value.
You can set this, by setting a value of true to the BigJuJuMapViewController.stickyPopups property (default is false).
Once we have included the package into our source file, then we can simply use the Storyboard Editor to create the instance:
Or just instantiate it directly:
self.bigJuJuMap = BigJuJuMapViewController()
self.navigationController?.pushViewController(self.bigJuJuMap, animated: true)
Once we have the view controller ready to go, we need to give it its dataset, which is simply an array of data items that conform to BigJuJuMapLocationProtocol. The test harnesses demonstrate this with simple datasets of US national and state parks.
This is demonstrated in the BJJM_LocationFactory struct, shared between the UIKit and SwiftUI test harness apps.
Simply set the BigJuJuMapViewController.mapData property to the array, and you're good to go. You may also want to set the map's region. The BigJuJuMap package exports some helpers, to make it easy to calculate from the data array.
You can directly access the MKMapView instance, by referencing the BigJuJuMapViewController.mapView computed property. The view controller's main view property is also the mapView, but referenced as a top-level UIView, not MKMapView.
You provide your own custom markers, by giving the BigJuJuMapViewController instance UIImages. These will be resized, in the map, but they should have a roughly 1:2 aspect ratio. If you will choose to have BigJuJuMapViewController.displayNumbers as true (the default), then the marker images should have a large blank area in the upper portion, that will not obscure labels displayed with the UIColor.systembackground color (inverse label color).
You provide the images by setting the BigJuJuMapViewController.singleMarkerImage and BigJuJuMapViewController.multiMarkerImage properties. Leaving them as nil, will cause the built-in (upside-down teardrop) marker to be used.
NOTE: If you want the same image to be used for both ("Custom 1," in the test harness apps), then you need to provide the same image to BOTH of the properties.
NOTE: Markers are assumed to have their "point" at the bottom, center of the image.
You can specify a font and color to be used, in data items. If these are present, the text in the popover for that item will be displayed with the color and font provided. Otherwise, the standard button font and color will be used.
You can set displayNumbers to false, and the numbers for aggregate markers will not display (for example, if you have intricate custom markers, the numbers will interfere).
You can set stickyPopups to true, and the popovers will not dismiss, when an item is selected.
SwiftUI has a very limited support for MapKit, which was why this package was written. In order to use it in SwiftUI, you need to wrap it in a UIViewControllerRepresentable instance. This is demonstrated in the SwiftUI test harness, in the
BJJM_BigJuJuMapViewController struct.
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.




















