-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[WIP] update iOS SDK guides #8354
[WIP] update iOS SDK guides #8354
Conversation
you want the attribute to be set to. | ||
constant values) or an `MGLStyleFunction` subclass. The style value object is a | ||
container for the raw value or function parameters that you want the attribute | ||
to be set to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting style functions is a subtask of configuring the map content’s appearance. I think the table mapping function types to MGLStyleFunction subclasses and MGLInterpolationMode values should be moved down here, to help progress the reader from simpler concepts to more advanced concepts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Especially since the tables currently repeat for each property.
`exponential` | `MGLInterpolationModeExponential` | ||
`interval` | `MGLInterpolationModeInterval` | ||
`categorical` | `MGLInterpolationModeCategorical` | ||
`identity` | `MGLInterpolationModeIdentity` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let’s split up this table into two: one for function types and the other for interpolation modes.
`zoom function` | `MGLCameraStyleFunction` | ||
`property function` | `MGLSourceStyleFunction` | ||
`zoom-and-property functions`| `MGLCompositeStyleFunction` | ||
`type` | `MGLInterpolationMode` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also a terminological difference. It’s worth mentioning that a “function type” is an “interpolation mode” up in the first table.
introduces `MGLInterpolationMode`. Individual style property documentation | ||
includes which subclasses of `MGLStyleFunction` are enabled for that property. | ||
|
||
In style JSON | In the SDK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function types (“zoom”, “property”, “zoom-and-property”) don’t appear in the style JSON, only in the style specification.
let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil) | ||
style.addSource(source) | ||
|
||
let stops = [0 : MGLStyleValue(rawValue: UIColor.yellow), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make this guide platform-agnostic, either by replacing UIColor with some other type like NSNumber that also exists on macOS, or by relying on type inference in Swift and the MGLColor
macro in Objective-C. Then we could move this guide to platform/darwin/docs/guides/.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MGLColor is a fine internal workaround, but I don’t believe we’ve encouraged its use publicly(?). Telling developers to use MGLColor has a couple issues:
- It’s not necessary for the vast majority of our developers (who are iOS-only).
- MGLColor’s purpose and action is opaque — actually using it has no technical downside, but the cognitive burden of learning what it is isn’t negligible. I’d expect a significant portion of our users to just assume that it’s the required way to define colors and not understand why that’s not the case.
At this point, I think it’s more reasonable to expect macOS developers to know UIColor doesn’t exist on that platform, rather than asking iOS developers to use a macro they don’t need.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely onboard with consistently using type inference in Swift, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Point taken about MGLColor being pedagogically problematic. In the Mapbox API Documentation examples in Objective-C, I took to using conditional compilation macros, which are better documented but even more poorly understood by less experienced developers.
What about bringing this guide under the same codegen mechanism that the “Information for Style Authors” guide uses?
- Move this guide to platform/darwin/docs/guides/Data-Driven Styling.md.ejs.
- Define a
cocoaPrefix
variable at the top. - Put a
<% cocoaPrefix %>
variable anywhere we’re currently sayingUI
. - Extend generate-style-code.js to also write out iOS- and macOS-specific versions of the guide.
- Run
make style-code
.
With this approach, the style-related guides would be more consistent with each other even at the code level. Additionally, it’ll give us the ability to put some of these (rather substantial) code examples in unit tests and insert them into this document automatically, ensuring that the examples stay current. We already use that approach for examples embedded in API documentation.
@@ -28,7 +28,7 @@ make sure the contents of these elements remain legible with the map view | |||
underneath. | |||
The user location annotation view, the attribution button, any buttons in | |||
callout views, and any items in the navigation bar are influenced by your | |||
application’s tint color, so choose a tint color that constrasts well with your | |||
application’s tint color, so choose a tint color that contrasts well with your |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
# Style functions and interpolation mode | ||
|
||
The runtime styling API introduced `MGLStyleFunction` to the iOS SDK. | ||
[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction` and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the DDS guide currently lives in platform/ios/docs/guides/, this link is broken in the macOS generated documentation. https://github.com/mapbox/mapbox-gl-native/pull/8354/files#r105503718 would be preferable, but if we can’t do that, then we should conditionalize this sentence on the platform. There are some examples above of only including a sentence on iOS or only on macOS.
let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil) | ||
style.addSource(source) | ||
|
||
let stops = [0 : MGLStyleValue(rawValue: UIColor.yellow), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MGLColor is a fine internal workaround, but I don’t believe we’ve encouraged its use publicly(?). Telling developers to use MGLColor has a couple issues:
- It’s not necessary for the vast majority of our developers (who are iOS-only).
- MGLColor’s purpose and action is opaque — actually using it has no technical downside, but the cognitive burden of learning what it is isn’t negligible. I’d expect a significant portion of our users to just assume that it’s the required way to define colors and not understand why that’s not the case.
At this point, I think it’s more reasonable to expect macOS developers to know UIColor doesn’t exist on that platform, rather than asking iOS developers to use a macro they don’t need.
|
||
##Data-Driven Styling | ||
|
||
Mapbox's data-driven styling features allow you to use data properties to style your maps. You can style objects within the same layer differently based on their individual attributes. This enables you to style icons, routes, parks, and more based on attributes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use smart quotes: Mapbox's
→ Mapbox’s
_Insert cool overview of things you can do!_ | ||
|
||
### How to use Data-Driven Styling | ||
This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) to illustrate to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](https://www.mapbox.com/ios-sdk/api/3.5.0-beta.1/working-with-geojson-data.html) guide. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to illustrateto style a map
|
||
There are three subclasses of `MGLStyleFunction`: | ||
|
||
* `MGLCameraStyleFunction` - For a style value that changes with zoom level. For example, you can make the radius of a circle to increase based on zoom level. In iOS SDK v3.4, a `MGLStyleFunction` referred to what is now a `MGLCameraStyleFunction`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
referred to what is now a
MGLCameraStyleFunction
.
This seems like unnecessary repetition. Could we say something like: “In iOS SDK v3.4, this function was called MGLStyleFunction
.”?
|
||
`MGLInterpolationModelExponential` creates a linear effect based on the values. The key value is the base for interpolation, and the style value is based on where an attribute value falls between two keys. | ||
|
||
The stops dictionary below, for example, shows colors that continuously shift from yellow -> orange -> red -> blue -> white based on the attribute value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let’s convert ->
to →
(or some other arrow symbol).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or “to”, since this is prose.
let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil) | ||
style.addSource(source) | ||
|
||
let stops = [0 : MGLStyleValue(rawValue: UIColor.yellow), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely onboard with consistently using type inference in Swift, though.
|
||
`MGLInterpolationModeInterval` creates a range using the keys stops dictionary. The range is from the given key to just less than the next key. The attribute values that fall into that range are then styled using the style value assigned to that key. | ||
|
||
When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 be yellow, 2.5 to just less than 5 would be orange, and so on. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow,
attributeName: "mag", | ||
options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)]) | ||
``` | ||
<img width="320" alt="screenshot 2017-02-28 19 14 40" src="https://cloud.githubusercontent.com/assets/12474734/23444472/30d4e8b4-fdea-11e6-8184-ad9631529c74.png"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately we can’t rely on GitHub to host these assets — be sure to commit and use the files required for this guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely! In the process of doing that. I copied this from a gist and am still working on optimizing the screenshots
``` | ||
<img width="320" alt="screenshot 2017-02-28 19 14 40" src="https://cloud.githubusercontent.com/assets/12474734/23444472/30d4e8b4-fdea-11e6-8184-ad9631529c74.png"> | ||
|
||
#####Categorical: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the colon in this heading.
|
||
|
||
|
||
#####Identity: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Colon.
|
||
`MGLInterpolationModelExponential` creates a linear effect based on the values. The key value is the base for interpolation, and the style value is based on where an attribute value falls between two keys. | ||
|
||
The stops dictionary below, for example, shows colors that continuously shift from yellow -> orange -> red -> blue -> white based on the attribute value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or “to”, since this is prose.
|
||
The stops dictionary below, for example, shows colors that continuously shift from yellow -> orange -> red -> blue -> white based on the attribute value. | ||
|
||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specifying swift
here would get us syntax coloring.
The stops dictionary below, for example, shows colors that continuously shift from yellow -> orange -> red -> blue -> white based on the attribute value. | ||
|
||
``` | ||
if let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL(string:)
only returns nil if the string is a malformed URL. Since the URL is formed from a string literal, we know it’s well-formed, so we can !
unwrap the optional without indenting everything below.
|
||
``` | ||
if let url = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson") { | ||
let symbolSource = MGLSource(identifier: "source") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if we were to indent, we should use four spaces for each level of indentation.
layer.circleColor = MGLStyleValue<UIColor>(interpolationMode: .exponential, | ||
sourceStops: stops, | ||
attributeName: "mag", | ||
options: [.defaultValue: MGLStyleValue<UIColor>(rawValue: .green)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reminds me: we should find a good place to mention the ability to use #8025, even if it isn’t important enough to show in a code example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, good point. I will see if I can adjust the example to show that. Alternatively, we can use it in an upcoming example. Or both.
you want the attribute to be set to. | ||
constant values) or an `MGLStyleFunction` subclass. The style value object is a | ||
container for the raw value or function parameters that you want the attribute | ||
to be set to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per #8025 (comment), let’s take this opportunity to point out that not every interpolation mode is available for every attribute. The developer should consult the documentation for an individual layout or paint attribute to see which function types and interpolation modes it supports.
3a5e79a
to
f9f084a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to update the jazzy.yml
files so the new guide shows up in the generated documentation side bar for iOS and macOS.
Also, there are changes to the For Style Author.md.ejs
template here that have not yet been picked up by make style-code
and committed as part of this PR. I looks like we plan to create a template for the DDS guide (per #8354 (comment)) so running make style-code
will happen in due time.
👍
|
||
Mapbox’s data-driven styling features allow you to use data properties to style your maps. You can style objects within the same layer differently based on their individual attributes. This enables you to style icons, routes, parks, and more based on attributes. | ||
|
||
![available bikes](img/data-driven-styling/citibikes.png) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Someday, it might be useful to include some designed images that combine a screenshot like this with a conceptual illustration of why these dots are special -- this could be something like an app screenshot on the left with a written function that maps a number to a color in the middle and an image of relevant tabular data on the right (just an idea).
Of course, nothing like this is required now but we might want to be on the lookout for images that end up in other parts of our docs or website and copy them back here.
|
||
The documentation for individual style properties will note which style functions are enabled for that property. | ||
|
||
####Stops |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that 4 #
s cause Stops
to become STOPS
in the generated documentation and that looks strange. Also, super nit, but we should probably format the headers consistently (add a space between the #
and the first character of the text)
|
||
Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key. | ||
|
||
####`MGLInterpolationMode` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the generated documentation, the four #
s capitalization issue combined with the formatting caused by the back ticks makes this looke like MGLINTERPOLATIONMODE
with a really thin font weight.
|
||
####`MGLInterpolationMode` | ||
|
||
The effect a key has on the style value is determined by the interpolation mode. There are four interpolation modes that can be used with a source style function: exponential, interval, categorical, and identity. You can also use exponential and interval interpolation modes with a camera style function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of calling out that "exponential and interval interpolation modes" can be used on a camera function, this might be a good place to add another table that shows which functions support which modes. That is:
camera: exponential & interval
source: all of them
composite: exponential, interval, categorial (but not identity)
3608a12
to
1de8180
Compare
Data-Driven Styling.md.ejs
Outdated
@@ -0,0 +1 @@ | |||
wat |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops that's from debugging! 😳
1de8180
to
987fb62
Compare
987fb62
to
0cbe2f7
Compare
const macOS = os === 'macOS'; | ||
const cocoaPrefix = iOS ? 'UI' : 'NS'; | ||
const layers = locals.layers; | ||
const renamedProperties = locals.renamedProperties; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of these variables appear to be unused. You can safely remove them.
- [ ] Cluster earthquakes as an example for camera function? | ||
- [ ] Clean up & optimize screenshots - replace with screenshots showing circles below symbol layer | ||
- [ ] Link API docs | ||
- [ ] Add cocoaprefix so this can be moved to darwin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this item is complete.
When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on. | ||
|
||
``` swift | ||
layer.circleColor = MGLStyleValue<<%- cocoaPrefix %>Color>(interpolationMode: .interval, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't necessary to specify NSColor/UIColor here, because Swift can infer the type from the type of circleColor.
@@ -166,6 +166,7 @@ layer | style layer | |||
property | attribute | |||
SDF icon | template image | |||
source | content source | |||
function type | interpolation mode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this entry up to keep the table alphabetized by the first column.
`property function` | `MGLSourceStyleFunction` | ||
`zoom-and-property functions`| `MGLCompositeStyleFunction` | ||
|
||
### <%- camelize(type) %> interpolation mode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This table doesn't need its own subheading, but a complete sentence introducing the concept of an interpolation mode is would help to make this document flow better.
fs.writeFileSync(`platform/ios/docs/guides/Data-Driven Styling.md`, ddsGuideMD({ | ||
os: 'iOS', | ||
renamedProperties: renamedPropertiesByLayerType, | ||
layers: layers, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of these variables, it looks like only os is in use.
@@ -239,6 +240,28 @@ whose names differ from the style specification are listed below: | |||
<% for (const type in renamedProperties) { -%> | |||
<% if (renamedProperties.hasOwnProperty(type)) { -%> | |||
|
|||
### <%- camelize(type) %> style functions | |||
|
|||
The runtime styling API introduced `MGLStyleFunction` to the <%- os %> SDK. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reads sort of like a release note. Let's cast this sentence in the present tense and talk about how the API includes style functions rather than introducing them.
Additionally, we have a tendency to use MGLStyleValue as an umbrella for both constants and functions. So even if we talk about the various style function subclasses, I think we should discuss the MGLStyleValue factory method that produces each kind of style function.
@@ -0,0 +1,133 @@ | |||
<!--- | |||
To do - JK: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these to-does done?
@@ -0,0 +1,125 @@ | |||
<!--- | |||
To do - JK: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Todoooooooooo.
@@ -0,0 +1,125 @@ | |||
<!--- | |||
To do - JK: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Toooooooooodoooooooo.
General note: these guides would benefit greatly from linking up the method/class names to their jazzy pages. ... which is something we should look into contributing upstream to jazzy. |
2.5 : MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.orange), | ||
5: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.red), | ||
7.5 : MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.blue), | ||
10 : MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.white)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also remove the initial tab indentation, as it’s indenting the entire block by one.
|
||
#### Interval | ||
|
||
`MGLInterpolationModeInterval` creates a range using the keys stops dictionary. The range is from the given key to just less than the next key. The attribute values that fall into that range are then styled using the style value assigned to that key. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keys stops dictionary
Is this a dictionary of stops for multiple keys? Pluralization is a little awkward, but if the meaning is correct then it’s probably OK.
|
||
``` swift | ||
let categoricalStops = ["earthquake" : MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.orange), | ||
"explosion" : MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.red), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the spaces before the colons and realign these lines.
|
||
![identity mode](img/data-driven-styling/identity.png) | ||
|
||
Resources: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Promote this to a bigger header, as in the bottom of the Runtime Styling guide.
Are these code snippets testable? We’re dynamically inserting tested snippets into header documentation, but I’m not sure we’ve done that yet for guides. /cc @ericrwolfe |
8c4a636
to
e6a1dfb
Compare
Re: testability I'd originally shied away from adding code snippets to the runtime styling guide out of concern for maintainability. But now that we have testable code examples we could certainly take a similar approach for the markdown guides. We might be able to rework the original script from this PR #7337 to scan through the guides directory and replace placeholder tokens in the markdown files. Note that the current examples script in cc @1ec5 |
We also took that approach for the examples in the headers because jazzy documentation links to specific lines in the headers based on the source code it consumes – we didn’t want the line numbers to go out of sync because of inserted code. But that problem doesn’t affect the Markdown guides. |
I opened a ticket so we can discuss how to make code snippets testable. #8461 |
For Style Authors
guide to include DDS related terminology- [ ] Update Runtime Styling guide as necessaryThe data-driven styling guide currently includes more code than the other previous guides, and may be more tutorial. It is intended to illustrate the differences between the different interpolation modes and how to use them, but it can be trimmed down.
Intended to partially address #8192 and the last two items on #7924.