aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Mapbox/Element.elm23
-rw-r--r--src/Mapbox/Expression.elm22
-rw-r--r--src/js/main.js48
3 files changed, 83 insertions, 10 deletions
diff --git a/src/Mapbox/Element.elm b/src/Mapbox/Element.elm
index 73b569f..13f5f00 100644
--- a/src/Mapbox/Element.elm
+++ b/src/Mapbox/Element.elm
@@ -1,4 +1,4 @@
-module Mapbox.Element exposing (map, css, MapboxAttr, token, id, maxZoom, minZoom, maxBounds, LngLat, renderWorldCopies, EventData, TouchEvent, eventFeaturesFilter, eventFeaturesLayers, onMouseDown, onMouseUp, onMouseOver, onMouseMove, onClick, onDblClick, onMouseOut, onContextMenu, onZoom, onZoomStart, onZoomEnd, onRotate, onRotateStart, onRotateEnd, onTouchEnd, onTouchMove, onTouchCancel, controlledMap, Viewport)
+module Mapbox.Element exposing (map, css, MapboxAttr, token, id, maxZoom, minZoom, maxBounds, LngLat, renderWorldCopies, featureState, EventData, TouchEvent, eventFeaturesFilter, eventFeaturesLayers, onMouseDown, onMouseUp, onMouseOver, onMouseMove, onClick, onDblClick, onMouseOut, onContextMenu, onZoom, onZoomStart, onZoomEnd, onRotate, onRotateStart, onRotateEnd, onTouchEnd, onTouchMove, onTouchCancel, controlledMap, Viewport)
{-| This library wraps a Custom Element that actually renders a map.
@@ -7,7 +7,7 @@ module Mapbox.Element exposing (map, css, MapboxAttr, token, id, maxZoom, minZoo
### Attributes
-@docs token, id, maxZoom, minZoom, maxBounds, LngLat, renderWorldCopies
+@docs token, id, maxZoom, minZoom, maxBounds, LngLat, renderWorldCopies, featureState
### Events
@@ -136,6 +136,25 @@ decodePair decoder =
)
+{-| This is a declarative API for controlling states on the features.
+
+The API takes a bunch of GeoJSON features (these can be returned from the event listeners for example). They should at a minimum have these properties defined:
+
+ - `source`
+ - `sourceLayer` (only for vector sources)
+ - `id` the feature's unique id
+
+Then you can give it a `List ( String, Value )` state. You can use this state infromation through the `Mapbox.Expression.featureState` expression.
+
+-}
+featureState : List ( Value, List ( String, Value ) ) -> MapboxAttr msg
+featureState =
+ List.map (\( feature, state ) -> Encode.list [ feature, Encode.object state ])
+ >> Encode.list
+ >> property "featureState"
+ >> MapboxAttr
+
+
-- Events
diff --git a/src/Mapbox/Expression.elm b/src/Mapbox/Expression.elm
index 6a9d9f7..af8298c 100644
--- a/src/Mapbox/Expression.elm
+++ b/src/Mapbox/Expression.elm
@@ -37,6 +37,7 @@ module Mapbox.Expression
, has
, count
, length
+ , featureState
, geometryType
, id
, properties
@@ -61,7 +62,7 @@ module Mapbox.Expression
, conditionally
, matchesStr
, matchesFloat
- , coallesce
+ , coalesce
, interpolate
, Interpolation(..)
, step
@@ -198,7 +199,7 @@ You can also use these functions to explicitly cast to a particular type:
### Feature data
-@docs geometryType, id, properties, getProperty, hasProperty
+@docs featureState, geometryType, id, properties, getProperty, hasProperty
### Decision
@@ -217,7 +218,7 @@ Logical operators:
Control flow:
-@docs ifElse, conditionally, matchesStr, matchesFloat, coallesce
+@docs ifElse, conditionally, matchesStr, matchesFloat, coalesce
### Ramps, scales, curves
@@ -268,7 +269,7 @@ Note however, that while being a strictly typed language, it has slighlty differ
- There is only a single number type. I have denoted it `Float`. You will notice that the `int` function takes an Elm int
value and converts it to an `Expression expr Float`.
- - All values may be `null`. There is no `Maybe` type. You can use the `coallesce` function to handle this.
+ - All values may be `null`. There is no `Maybe` type. You can use the `coalesce` function to handle this.
- There is no distinction between `List`, `Array`, and tuples. Hence all collections are labeled as `Array`.
- Dictionaries are called `Object`. The keys are always `String`, but the values can be of mixed types. Hence retrieving
values from them makes code untyped.
@@ -822,6 +823,13 @@ call name args =
Expression (Json.Encode.list (Json.Encode.string name :: args))
+{-| Retrieves a property value from the current feature's state. Returns null if the requested property is not present on the feature's state. A feature's state is not part of the GeoJSON or vector tile data, and must be set programmatically on each feature. Note that `featureState` can only be used with paint properties that support data-driven styling.
+-}
+featureState : Expression exprType String -> Expression DataExpression any
+featureState =
+ call1 "feature-state"
+
+
{-| Gets the feature's geometry type: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon.
-}
geometryType : Expression DataExpression String
@@ -993,9 +1001,9 @@ any =
{-| Evaluates each expression in turn until the first non-null value is obtained, and returns that value.
-}
-coallesce : List (Expression exprType outputType) -> Expression exprType outputType
-coallesce =
- calln "coallesce"
+coalesce : List (Expression exprType outputType) -> Expression exprType outputType
+coalesce =
+ calln "coalesce"
{-| The ternary operator:
diff --git a/src/js/main.js b/src/js/main.js
index d105d3e..b1ec6fb 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -103,6 +103,50 @@ function wrapElmApplication(elmApp, settings = {}) {
this._pitch = value;
}
+ get featureState() {
+ return this._featureState;
+ }
+ set featureState(value) {
+ // TODO: Clean this up
+ function makeId({id, source, sourceLayer}) {
+ return `${id}::${source}::${sourceLayer}`;
+ }
+ if (this._map) {
+ const map = new Map(this._featureState.map(([feature, state]) => [makeId(feature), {feature, state}]));
+ value.forEach(([feature, state]) => {
+ const id = makeId(feature);
+ if (map.has(id)) {
+ const prevValue = map.get(id).state;
+ const keys = Object.keys(prevValue);
+ let newValue = {};
+ keys.forEach(k => {
+ if (state[k] === undefined) {
+ newValue[k] = undefined;
+ }
+ });
+ this._map.setFeatureState(
+ feature,
+ Object.assign(newValue, state)
+ );
+ } else {
+ this._map.setFeatureState(feature, state);
+ }
+ map.delete(id);
+ });
+
+ map.forEach(({feature, state}) => {
+ const keys = Object.keys(state);
+ let newValue = {};
+ keys.forEach(k => {
+ newValue[k] = undefined;
+ });
+ this._map.setFeatureState(feature, newValue);
+ });
+ }
+
+ this._featureState = value;
+ }
+
addEventListener(type, fn, ...args) {
if (this._map) {
var wrapped;
@@ -236,7 +280,9 @@ function wrapElmApplication(elmApp, settings = {}) {
if (elmApp.ports && elmApp.ports.elmMapboxOutgoing) {
function processOptions(opts) {
if (opts.easing) {
- return Object.assign({}, opts, {easing: options.easingFunctions[opts.easing]});
+ return Object.assign({}, opts, {
+ easing: options.easingFunctions[opts.easing]
+ });
}
return opts;
}