Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Moremi Vannak
Moremi Vannak

Posted on • Edited on

     

Display and Edit Google Map in Elm

Using google map in elm is a bit tricky. This tutorial will show how to initialize the map, edit the map, and get the map data through port.

Preview:https://chmar77.github.io/elm-google-map-tutorial/

Requirement

This tutorial aims for those who already familiar with elm.

The tool that is needed:

  • elm:npm install -g elm
  • elm-live:npm install -g elm-live

Setting up project

  • Create following folder structure
elm-google-map├── src│   ├── Main.elm│   ├── Map.elm│   └── Port.elm└── index.html
  • In index.html, copy the following code
<!DOCTYPE html><html><head><metaname="viewport"content="width=device-width, initial-scale=1"><title>Elm Google Map</title><style>html,body{margin:0;padding:0;}#map{height:300px;width:300px;}#edit-map{height:300px;width:300px;}.hidden{visibility:hidden;height:0;width:0;}</style></head><body><scriptsrc="dist/elm.js"></script><script>varapp=Elm.Main.fullscreen();</script></body></html>
  • Run:elm-package install
  • Copy the following code in Main.elm
moduleMainexposing(..)importHtmlexposing(..)importHtml.Attributesexposing(..)importHtml.Eventsexposing(..)main:ProgramNeverModelMsgmain=Html.program{init=init,update=update,view=view,subscriptions=subscriptions}typealiasModel={title:String}init:(Model,CmdMsg)init=({title="Elm Google Map"},Cmd.none)typeMsg=NoOpupdate:Msg->Model->(Model,CmdMsg)updatemsgmodel=casemsgofNoOp->(model,Cmd.none)view:Model->HtmlMsgviewmodel=div[][h1[][text"Elm Google Map"]]subscriptions:Model->SubMsgsubscriptionsmodel=Sub.none
  • In elm-package.json, change the source-directories from "." to "src"
 "source-directories": [        "src" ],
  • Runelm-live src/Main.elm --output=dist/elm.js in the root folder of our project and go tohttp://localhost:8000/ to see our initialized project

  • If you see 'Elm Google Map' then it means everything is working fine

Creating Map Module

  • Copy the following code:
moduleMapexposing(Model,JsObject,init,modify,toJsObject)typeModel=Internal{latitude:Float,longtitude:Float}init:Modelinit=Internal{latitude=11.55408504200135,longtitude=104.910961602369}modify:Float->Float->Model->Modelmodifylatitudelongtitude(Internalmodel)=Internal{model|latitude=latitude,longtitude=longtitude}typealiasJsObject={lat:Float,lng:Float}toJsObject:Model->JsObjecttoJsObject(Internalmodel)={lat=model.latitude,lng=model.longtitude}

Here we are trying to make our module hidden. Record that uses the Model type, when accessing or modifying will need the function from the module. It cannot access the record directly.

Port Module

portmodulePortexposing(..)importMap-- Outgoing PortportinitializeMap:Map.JsObject->CmdmsgportinitializeEditMap:Map.JsObject->CmdmsgportmoveMap:Map.JsObject->Cmdmsg-- Incoming PortportmapMoved:(Map.JsObject->msg)->Submsg

Here we divides out port into 2 parts, incoming and outgoing.

Javascript part

  • add google map script below elm.js script
<script src="https://maps.googleapis.com/maps/api/js?key={{your-api-key}}"></script>
  • pass the following code belowvar app = Elm.Main.fullscreen(); in index.html
app.ports.initializeMap.subscribe(function(pos){console.log("Initialize Map")varmapDiv=document.getElementById('map');console.log(pos);if(mapDiv){// MapvarmyLatlng=newgoogle.maps.LatLng(pos);varmapOptions={zoom:15,center:myLatlng};vargmap=newgoogle.maps.Map(mapDiv,mapOptions);// Markervarmarker=newgoogle.maps.Marker({position:myLatlng,title:"Hello World!"});marker.setMap(gmap);// Listening for map move eventapp.ports.moveMap.subscribe(function(pos){console.log("received",pos);varmyLatlng=newgoogle.maps.LatLng(pos);gmap.setCenter(myLatlng);marker.setPosition(myLatlng)});}else{console.log("Cant find map dom");}});

Here we just create an event listening to initializeMap port from elm. The moveMap event will be used later on when we try to edit the map.

Back to Main Module

  • We can import out Map and Port Module
importMapimportPort
  • Update our Model, and init
typealiasModel={title:String,map:Map.Model}
init:(Model,CmdMsg)init=({title="Elm Google Map",map=Map.init},Map.init|>Map.toJsObject|>Port.initializeMap)
  • Finally update our view
view:Model->HtmlMsgviewmodel=div[][h1[][textmodel.title],p[][text<|"Current pointer"++(toString<|Map.toJsObjectmodel.map)],div[][div[id"map"][]]]
  • If your are not running elm-live, runelm-live src/Main.elm --output=dist/elm.js again and go tohttp://localhost:8000/
  • If you are able to see the map, then everything is working as expected

Editing Map

  • First add additional javascript below the previous one in index.html
app.ports.initializeEditMap.subscribe(function(pos){console.log("Initialize Edit Map")varmapDiv=document.getElementById('edit-map');console.log(pos);if(mapDiv){// MapvarmyLatlng=newgoogle.maps.LatLng(pos);varmapOptions={zoom:15,center:myLatlng};vargmap=newgoogle.maps.Map(mapDiv,mapOptions);// Markervarmarker=newgoogle.maps.Marker({position:myLatlng,title:"Hello World!"});marker.setMap(gmap);gmap.addListener('drag',function(){varnewPos={lat:gmap.getCenter().lat(),lng:gmap.getCenter().lng()};marker.setPosition(newPos);app.ports.mapMoved.send(newPos);});}else{console.log("Cant find edit map dom");}});
  • Back in Main.elm, add State type to our Model so that we can edit the map
typealiasModel={title:String,map:Map.Model,state:State}typeState=View|Editinit:(Model,CmdMsg)init=({title="Elm Google Map",map=Map.init,state=View},Map.init|>Map.toJsObject|>Port.initializeMap)
  • Then add edit button and editView in the view function
view:Model->HtmlMsgviewmodel=div[][h1[][textmodel.title],p[][text<|"Current pointer"++(toString<|Map.toJsObjectmodel.map)],div[][div[id"map"][],button[onClickEditMap][text"Edit"]],editViewmodel]
  • Copy the following code for the editView
editView:Model->HtmlMsgeditViewmodel=div[class<|casemodel.stateofView->"hidden"Edit->""][hr[][],div[id"edit-map"][],button[onClickSaveEditMap][text"Done"]]
  • We also want to listen to the drag event when editing. We can do that by modifying our subscription
subscriptions:Model->SubMsgsubscriptionsmodel=Port.mapMovedOnEditMapDrag
  • As you can see about, we create a few new msg and we will have to create and handle them
typeMsg=NoOp|EditMap|OnEditMapDragMap.JsObject|SaveEditMap
  • In our update function
update:Msg->Model->(Model,CmdMsg)updatemsgmodel=casemsgofNoOp->(model,Cmd.none)EditMap->({model|state=Edit},model.map|>Map.toJsObject|>Port.initializeEditMap)OnEditMapDrag{lat,lng}->({model|map=Map.modifylatlngmodel.map},Cmd.none)SaveEditMap->({model|state=View},model.map|>Map.toJsObject|>Port.moveMap)

This is it

The source code is here:https://github.com/chmar77/elm-google-map-tutorial
Preview:https://chmar77.github.io/elm-google-map-tutorial/

That's the end of the tutorial. If something is not working for you, or needs explanation of certain things you do not understand, comment down below.

Thanks for reading !!!

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Enthusiastic Functional Programmer, specialized in Haskell, Purescript, Elm...
  • Location
    Phnom Penh, Cambodia
  • Education
    Zaman University
  • Work
    Okoone Web Developer
  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp