port module Example04 exposing (main) import Browser import Html exposing (div, text) import Html.Attributes exposing (style) import Html.Lazy exposing (lazy2) import Http import Json.Decode import Json.Encode import LngLat exposing (LngLat) import Map import MapCommands import Mapbox.Cmd.Option as Opt import Mapbox.Element exposing (..) import Mapbox.Expression as E exposing (false, float, int, str, true) import Mapbox.Layer as Layer import Mapbox.Source as Source import Mapbox.Style as Style exposing (Style(..), StyleDef) port elmMapboxIncoming : (Json.Encode.Value -> msg) -> Sub msg main = Browser.document { init = init , view = view , update = update , subscriptions = subscriptions } subscriptions : Model -> Sub Msg subscriptions _ = elmMapboxIncoming MapCenter type alias Model = { position : LngLat , zoom : Float , features : List Json.Encode.Value , jsonMap : Maybe StyleDef } init : () -> ( Model, Cmd Msg ) init () = ( { position = LngLat 0 0 , zoom = 13.8 , features = [] , jsonMap = Nothing } , fetchStyle "mapbox://styles/yourstile/ck0dvc9zq0g2v1cmw9xg18pu7" "pk.eyJ1Ijoi..." ) type Msg = Hover EventData | Click EventData | MapCenter Json.Encode.Value | LoadedStyle (Result Http.Error String) fetchStyle styleUrl token = String.replace "mapbox://styles/" "https://api.mapbox.com/styles/v1/" styleUrl ++ "?access_token=" ++ token |> Http.getString |> Http.send LoadedStyle update msg model = case msg of Hover { lngLat, renderedFeatures } -> ( { model | position = lngLat, features = renderedFeatures }, Cmd.none ) Click { lngLat, renderedFeatures } -> ( { model | position = lngLat, features = renderedFeatures }, MapCommands.fitBounds [ Opt.linear True, Opt.maxZoom 10 ] ( LngLat.map (\a -> a - 0.2) lngLat, LngLat.map (\a -> a + 0.2) lngLat ) ) MapCenter e -> ( model, Cmd.none ) LoadedStyle (Ok style) -> ( { model | jsonMap = case ( Json.Decode.decodeString Style.decode style , Json.Decode.decodeString Style.decodeMiscDef style ) of ( Ok mapbox, Ok misc ) -> Just { mapbox | misc = Style.miscDefToList misc } _ -> Nothing } , Cmd.none ) LoadedStyle (Err e) -> ( model, Cmd.none ) geojson : Json.Encode.Value geojson = Json.Decode.decodeString Json.Decode.value """ { "type": "FeatureCollection", "features": [ { "type": "Feature", "id": 1, "properties": { "name": "Bermuda Triangle", "area": 1150180 }, "geometry": { "type": "Polygon", "coordinates": [ [ [-64.73, 32.31], [-80.19, 25.76], [-66.09, 18.43], [-64.73, 32.31] ] ] } } ] } """ |> Result.withDefault (Json.Encode.object []) hoveredFeatures : List Json.Encode.Value -> MapboxAttr msg hoveredFeatures = List.map (\feat -> ( feat, [ ( "hover", Json.Encode.bool True ) ] )) >> featureState showMap mapbox features = case mapbox of Just style -> map [ maxZoom 150 , onMouseMove Hover , onClick Click , id "my-map" , eventFeaturesLayers [ "changes" ] , hoveredFeatures features ] (Style { style | layers = style.layers ++ [ Layer.fill "changes" "changes" [ Layer.fillOpacity (E.ifElse (E.toBool (E.featureState (str "hover"))) (float 0.9) (float 0.1)) ] ] , sources = style.sources ++ [ Source.geoJSONFromValue "changes" [] geojson ] } ) Nothing -> Html.text "Nothing" view model = { title = "Mapbox Example" , body = [ css , div [ style "width" "100vw", style "height" "100vh" ] [ lazy2 showMap model.jsonMap model.features , div [ style "position" "absolute", style "bottom" "20px", style "left" "20px" ] [ text (LngLat.toString model.position) ] ] ] }