Displaying articles with tag

Marker Creation with extra cruft! (rails with mappa Part IV)

Posted by nito, Wed Jan 02 12:31:00 UTC 2008

The story so far: If you’ve been reading along, you’ll have learned how to add maps, markers, and listeners, and it’s all been too easy: a few lines in a controller, a bit of modular reusable javascript, the merest of touches to your views.

‘Okay’, I can hear you say, ‘that’s all well and good, but I want to do more with my markers! I want to be able to click on my marker and have it reveal a nice little piece of html formatted text! I want to be able to use my own personal type of marker shaped like a truck!! I want to be able to click on the map and be teleported there in real time!!’

Okay, okay, simmer down, we’re getting there.

The javascript

We are going to create our marker in much the same way as we created our listener in Part III, using an external, modular, re-usable javascript function.

Create a new file called ‘_createWithIconAndHtml.mjs’ in your mapping/public/javascripts/map_js directory and cut and paste the following javascript into that file.

function createMarker(point,html,icon_image) {
              var icon = new GIcon();

              icon.image =   icon_image  ;

              icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
              icon.iconSize = new GSize(12, 20);
              icon.shadowSize = new GSize(22, 20);
              icon.iconAnchor = new GPoint(6, 20);
              icon.infoWindowAnchor = new GPoint(5, 1);

              var marker = new GMarker(point,icon);

              GEvent.addListener(marker, "click", function() {
                marker.openInfoWindowHtml(html);
              });
            return marker;
          }

We didn’t have to give it such a long name, but 1) it’s explicit and expressive and 2) it gives your fingers more exercise than just cut and paste, and as I’ve made this all so easy for you I thought I’d give you some work to do to stop you falling asleep.

You will also notice that the name of the function is different from the name of the file. This merely demonstrates that the two do not have to be the same.

The image

Clearly, we are going to need an image for our marker. You wanted a truck (or perhaps a tardis!), but in light of recent news regarding climate change, I’m not going to give you the truck as I’m imposing a truck moratorium on my maps until I can determine the effect it has on my carbon footprint, and as for the tardis, well, I suspect there’ll be copyright issues there.

But, here’s a nice innocuous blue marker spot you can use: right click (or control click, or whatever fancy clicky-button-press your own brand of OS uses) and save it to gmapping/public/images

The Controller code

Once again, edit your map_controller file and copy the following the method into the file.

def scripted_marker_with_icon_and_html

    @page_title = action_name

    @gmap = Mappa::GMap.new()

    @gmap.api_key = @@key

    @gmap.lat = 51.775362610
    @gmap.lng = -0.00100011

    @gmap.zoom = 16
    @gmap.add_control(:control => 'large')
    @gmap.add_control(:control => 'type')

    marker_lat = 51.77530
    marker_lng = -0.002


    # Here we read our _createWithIconAndHtml.mjs file, telling gmap we're using this 

    @gmap.use_marker_code('createWithIconAndHtml', :with_args => [:point, :html, :icon_image])

    incident_point = Mappa::GLatLng.new(:lat => marker_lat, :lng => marker_lng)
    @gmap.add_marker(:point => incident_point, :create_with => 'createWithIconAndHtml', :html => "'Click <a href="#">here</a> to teleport!'", :icon_image => "'/images/marker6.png'")    

    render :template => "map/index"
  end

Let’s look at that again. What did we add to our controller?

@gmap.use_marker_code('createWithIconAndHtml', :with_args => [:point, :html, :icon_image])

That one line tells Mappa to use the _createWithIconAndHtml.mjs file to find the create marker code.

@gmap.add_marker(:point => incident_point, :create_with => 'createWithIconAndHtml', :html => "'Click <a href="#">here</a> to teleport!'", :icon_image => "'/images/marker6.png'")

And that’s our one line, nice and nifty, little add_marker code. I don’t think it needs much explanation for now, suffice to say: notice the way we use :html, :point and :icon_image, and how it ties into the :with_args argument of gmap.use_marker_code.

And that’s it. We’re all done now. Try it out: http://localhost:3000/map/scripted_marker_with_icon_and_html and don’t forget to click on the marker to see the html!

“Hey!” I hear you bellow ( Shhhh…. for it is the day after new year and some of us still have a sore head!)

“hey” I hear you whisper (thank you!), “What about the teleporting?”

Oh yes, teleporting. I did mention teleporting, didn’t I. Well, I’ve got to leave you something to do, or it’s all just too easy, isn’t it! So I’m leaving the teleportation code as an exercise for the reader.

Happy new year.

2 comments | Filed Under: Geekliness Tutorial | Tags:

How do you handle that 'Click click click...' (rails with mappa part III)

Posted by nito, Tue Jan 01 02:09:00 UTC 2008

So, we’ve added a marker via code in our controller, we’ve added those google map controls, we’ve put our javascript map code into the header (thus allowing us to take better advantage of the ‘Gunload’ garbage collection method) but we want to do more. We crave more power…We’re itching to handle map clicks and write our own, more complex, more specific Javascript. Oh what fun!

So, here goes…

User story: When I click on the map, i want it to place a marker on the spot I click. When I click on a marker i want it to delete that marker.

First we want some Javascript. A function that fulfills the user story. Here’s one I baked earlier:

function addMapPinClick(marker, point) {
          if (marker) {
            gmap.removeOverlay(marker);

            } else {
              gmap.addOverlay(new GMarker(point));
            }  
      }

Okay, so the next question must surely be: ‘where do we put it?’ Navigate to your mapping/public/javascripts directory and create a new directory called map_js. Inside that directory create a file called ‘_addMapPinClick.mjs’.

Now, copy and paste that little function above, into your new _addMapPinClick.mjs file. And that’s our Javascript done. Really. No more. I promise.

Now let’s edit mapping/app/controllers/map_controller.rb. We are going to create a new method called map_with_onclick

def map_with_onclick

    # Because I can't be bothered to think too hard, let alone think up a name, 
    # I've let rails do my thinking for me and used action_name to get hold of the
    # name of this action, and store it in the @page_title instance variable. 
    @page_title = action_name

    @gmap = Mappa::GMap.new()

    # Much better to store our api key in one place. Here we are using a class variable 
    # that we'll place at the top of this controller file (after the class definition). We may 
    # eventually decide it's best placed in the application.rb
    @gmap.api_key = @@key

    @gmap.lat = 51.775362610
    @gmap.lng = -0.00100011

    @gmap.zoom = 16
    @gmap.add_control(:control => 'large')
    @gmap.add_control(:control => 'type')

    #This is where we read in our function
    @gmap.include_funcs('addMapPinClick')

    # Here we add our listener. The method call is pretty self-explanatory, methinks.
    @gmap.add_listener( :element => 'gmap', :action => 'click', :method => 'addMapPinClick')

    # Once again, we're doing nothing special here, so why not reuse our 
    # marker_onload template, eh? :-)
    render :template => "map/marker_onload"

  end

The top of that file now also needs to have the @@key variable. Once you’ve made your edits, the top of the controller file should look like this:

class MapController < ApplicationController

  #This is the google map API key for localhost:3000. Don't forget to change it when you need to!
  @@key = 'ABQIAAAArjtwNyA-0TDmcb74hMzhHBTJQa0g3IQ9GZqIMmInSLzwtGDKaBRSDWK-cqMmi3YB5dD-8a6Kwe1Qmg'

Now go back to your browser and try it out: http://localhost:3000/mapping/map_with_onclick.

Neat, eh?

Next: adding markers with extra cruft!

0 comments | Filed Under: Geekliness Tutorial | Tags:

Making your mark on the World (rails with mappa - Part II)

Posted by nito, Mon Dec 31 02:28:00 UTC 2007

Now let’s look at adding markers, special google navigation controls, onload functionality and then let’s refactor and add a little Rails DRYness.

1) Adding a marker

Open map_controller.rb (you will find it in gmapping/app/controllers) in your favourite editor (no, let’s not go there!). Add the following method:

def marker
    @page_title = 'My first map with marker!'

    @gmap = Mappa::GMap.new()

    # the gmap api key for localhost:3000 - remember to change this!
    @gmap.api_key = "ABQIAAAArjtwNyA-0TDmcb74hMzhHBTJQa0g3IQ9GZqIMmInSLzwtGDKaBRSDWK-cqMmi3YB5dD-8a6Kwe1Qmg"
    @gmap.lat = 51.775362610
    @gmap.lng = -0.00100011

    # now for the lat and lng of the marker we want to add. 
    marker_lat = 51.78530
    marker_lng = -0.015
    #create our marker 
    marker = Mappa::GLatLng.new(:lat => marker_lat, :lng => marker_lng)

    #add the marker to the map.
    @gmap.add_marker(:point => marker)    
    @gmap.zoom = 12

    @gmap.onload = false

  end

Now let’s create the view file. This is very easy, because there are no changes to the file aside from the dynamically created javascript. By default, rails will look for a marker.rhtml file in gmapping/app/views/map. So, let’s copy our index.rhtml to marker.rhtml.

That’s it. go and try it.: http://localhost:3000/map/marker.

2) Adding google map controls and drying it up a bit

The method for adding controls is: Mappa.add_control(:control => ‘controltype’) The control can be one of: small, large, type, overview.

edit the map_controller.rb again and add the following lines to the bottom of the marker method you added (see above).

@gmap.add_control(:control => 'small')
    @gmap.add_control(:control => 'type')
    @gmap.add_control(:control => 'overview')

Because there was no difference between our index.rhtml and our marker.rhtml, we didn’t really need it, so let’s tell rails to render the same layout the for the marker method as we used for the index method. Add the following line to the very end of the method, just above the ‘end’ statement:

render :template => 'map/index'

Your marker method should now look like this:

def marker
    @page_title = 'My first map with marker!'

    @gmap = Mappa::GMap.new()

    # the gmap api key for localhost:3000 - remember to change this!
    @gmap.api_key = "ABQIAAAArjtwNyA-0TDmcb74hMzhHBTJQa0g3IQ9GZqIMmInSLzwtGDKaBRSDWK-cqMmi3YB5dD-8a6Kwe1Qmg"
    @gmap.lat = 51.775362610
    @gmap.lng = -0.00100011

    # now for the lat and lng of the marker we want to add. 
    marker_lat = 51.78530
    marker_lng = -0.015

    #create our marker 
    marker = Mappa::GLatLng.new(:lat => marker_lat, :lng => marker_lng)

    #add the marker to the map.
    @gmap.add_marker(:point => marker)    
    @gmap.zoom = 12

    @gmap.onload = false
    @gmap.add_control(:control => 'small')
    @gmap.add_control(:control => 'type')
    @gmap.add_control(:control => 'overview')

    render :template => 'map/index'

  end

Take another look: http://localhost:3000/map/marker

3) Getting it all out of the body, into the head and using onload (and introducing partials and helpers!)

To call something via onload in the header of our page, to actually include that content into the header section, and to keep it all nice and DRY requires a few new steps.

First let’s edit our layout file. open gmapping/app/views/layout/map.rhtml in your editor and replace the line that contains the body tag:

<body>

with

<%= body_tag_creator %>

the ‘body_tag_creator’ is something new: a helper method. change directory to: mapping/app/helpers and open the application_helper.rb file in your favourite editor, and add the body_tag_creator method. When you’ve finished, your file should look like this:

module ApplicationHelper

  def body_tag_creator
    if !@gmap.nil? && @gmap.onload
      '<body onload="' + @gmap.onload_func_name + '()" onunload="GUnload">'
    else
      '<body>'
    end
  end

end

This new method is now available to every view. We could also have restricted it to those views generated by the map_controller, by only adding it to the map_helper.rb. Helpers help us to keep view generating code out of our view files.

Add the following method to your map_controller.rb:

def marker_onload
    @page_title = 'My first map with marker!'

    @gmap = Mappa::GMap.new()

    # the gmap api key for localhost:3000 - remember to change this!
    @gmap.api_key = "ABQIAAAArjtwNyA-0TDmcb74hMzhHBTJQa0g3IQ9GZqIMmInSLzwtGDKaBRSDWK-cqMmi3YB5dD-8a6Kwe1Qmg"
    @gmap.lat = 51.775362610
    @gmap.lng = -0.00100011

    # now for the lat and lng of the marker we want to add. 
    marker_lat = 51.78530
    marker_lng = -0.015

    #create our marker 
    marker = Mappa::GLatLng.new(:lat => marker_lat, :lng => marker_lng)

    #add the marker to the map.
    @gmap.add_marker(:point => marker)    

    marker2_lat = 51.7900
    marker2_lng = -0.025

    #create our marker 
    marker2 = Mappa::GLatLng.new(:lat => marker2_lat, :lng => marker2_lng)

    #add the marker to the map.
    @gmap.add_marker(:point => marker2)    

    @gmap.zoom = 12

    @gmap.add_control(:control => 'large')
    @gmap.add_control(:control => 'type')
    @gmap.add_control(:control => 'overview')

  end

Now let’s create a new view, and in the process introduce the rails :partial template.

create a file called marker_onload.rhtml in gmapping/app/views/map. Edit that file and add the following layout:

<%= render :partial => 'headers' %>
<div style="height:400px;width:400px" id="gmap"></div>

That’s it for the view, now let’s look at the partial. The name of the partial, according to the render call in the marker_onload.rhtml file, is ‘headers’. All partial file names start with an underscore, so, create a file called _headers.rhtml in gmapping/app/views/map. Edit that file and add the following layout:

<% content_for :map_headers do %>
    <%= map_header(@gmap) %>
    <%= map_body(@gmap) %>
<% end %>

Why did we use a partial? Partials are generally used for small chunks of oft used code. In this case we are saving ourselves repetitive use of those four lines of markup, as it’s highly likely we will be using them again. Notice also, that the map_body mappahelper method is now included along with map_header in the section of the web page. We’re doing this because we are now going to be calling our map generating javascript from an onload that looks to the section for its code.

And that’s all for now folks. If you’ve been following along, you should be able to see what you’ve done by point your browser to: http://localhost:3000/map/marker_onload

Next: handling map events, creating more custom marker creation methods and reading from external .mjs files

0 comments | Filed Under: Geekliness Tutorial | Tags: