Lose the faff, bring back the fun with toepoke.co.uk

Mapsed.js!

Google maps & places jQuery integration plug-in

Find Out More

Google Map Picker

On my little website I need to allow users to be able to pick somewhere to play football.

Couldn't really find anything that did what I was after (even Google Map Engine didn't quite do it) so I built mapsed.js
(MAP Select, Edit & Delete).

As well as selecting places, you can add/edit ones to integrate with your own database; check out the examples to see what else it does.

Show me the money demos ...

Examples

Loading Places

Here we're illustrating loading places from our own database, and telling mapsed what places to draw (via the showOnLoad array).

The top marker stores a lookup to a Google Place place_id, the bottom one stores a custom place object.

show/hide code illustration

$("#custom-places").mapsed({
  showOnLoad:
  [
    // City Varieties
    {
      // flag that this place should have the tooltip shown when the map is first loaded
      autoShow: true,
      // flags the user can edit this place
      canEdit: false,
      canDelete: false,
      lat: 53.798823,
      lng:-1.5426760000000286,
      place_id: "ChIJQd3IwBtceUgRha6laiANoro"
    },
    // Random made up CUSTOM place
    {
      // flag that this place should have the tooltip shown when the map is first loaded
      autoShow: true,
      lat: 53.79,
      lng:-1.5426760000000286,
      name: "Somewhere",
      street: "Over the rainbow, Up high way"
    }
  ]
});									
									

So far, so uninteresting ☺


Place Picker

Ooooh, this time there's a Select button!

show/hide code illustration

$("#place-picker").mapsed({
  // allow user to select somewhere
  onSelect: function(mapsed, details) {
    var msg = 
      "Name: " + details.name + 
      "Address: " + 
        details.street + ", " + 
        details.town + ", " + 
        details.area + ", " + 
        details.postCode +
      "website: " + details.website +
      "more: " + details.url +
      "Tel: " + details.telNo
    ;
    mapsed.showMsg("Place selected!", msg);
      
    // indicate tip should be closed
    return true;
  },
  
  showOnLoad: 
  // City Varieties
  {
    // flag that this place should have the tooltip shown when the map is first loaded
    autoShow: true,
    lat: 53.798823,
    lng:-1.5426760000000286,
    place_id: "ChIJQd3IwBtceUgRha6laiANoro"
  },

	// Defines header and footers to be applied to the 
	// ... select/edit/delete tooltips shown to the user
	getHeaderTemplate: function(marker, isEditing) {
		// You can have a different header for
		// each "markerType".  Supported customisations are:
		// "custom" - Where your user has previously added a marker
		// "add" - Where your user has click "add" to create a new marker
		// "google" - Where your user has clicked on a marker found via Google Places APi
		var markerType = marker.markerType;
		var mode = (isEditing ? "edit" : "view");

		return `<center>${markerType} ${mode} header</center>`.toUpperCase();
	},

});
								

The Select button is turned on simply by implementing the onSelect callback.

Note you can also add your own headers & footers too.


Adding Places

Being able to Select places is pretty useful, but a waste of time if we can't create them!

This time we have a new icon at the top-right of the map. Simply click + to add a new place. The marker can be dragged around to refine the location.

There's noddy validation support too, try hitting Save without a Name property.

show/hide code illustration

function updateDatabase(m, newPlace) {
  var missing = [];

  // detect errors starting at bottom
  // ... we only have space for one error at a time, so this way we'll report 
  // ... from the top down
  if (newPlace.postCode === "") missing.push("postcode");
  if (newPlace.street === "")   missing.push("street");
  if (newPlace.name === "")     missing.push("name");

  // anything missing?
  if (missing.length > 0) {
    // return the error message so the callback doesn't progress
    return "Required: " + missing.join();
  }

  if (newPlace) {
    if (!newPlace.userData) {
    	// simulate a primary key being save to a db
    	newPlace.userData = parseInt(Math.random() * 100000);
    }
    
    var title = "";
    var msg = 
      "userData: " + newPlace.userData + 
      "<br />name: " + newPlace.name +
      "<br />street: " + newPlace.street + ", " + 
        newPlace.area + ", " + 
        newPlace.town + ", " + newPlace.postCode + 
      "<br />telNo: " + newPlace.telNo + 
      "<br />website: " + newPlace.website + 
      "<br />more: " + newPlace.url
    ;
    if (newPlace.place_id) {
      msg += "<br />Place_id: " + details.place_id
    }
    if (newPlace.markerType == "new") {
      title = "New place added!";
    } else {
      title = "Place saved!";
    }
    m.showMsg(title, msg);
  }

  // indicate form was OK and saved
  return "";
}

$("#add-places").mapsed({

  // Enables edit of custom places (to your web application, not Google Maps!)
  // ... again the presence of the callback enables the functionality
  onSave: function(m, newPlace) {
    return updateDatabase(m, newPlace);
  },
  // Adds the "+" button to the control bar at the top right of the map
	// And wires up the save event for "new" places
  onAddSave: function(m, newPlace) {
    return updateDatabase(m, newPlace);
  }

	// .... >/snip<
});
								

Notice once we've saved a place, we get an Edit button to make changes.

Simply wire up the onAddSave callback to save the new place. Wiring up the event also enables the icon


Deleting Places

Completing our cruddy demos we can delete places too.

show/hide code illustration

  $("#delete-places").mapsed({
    showOnLoad: 
    [
      // City Varieties
      {
        autoShow: true,
        canEdit: true,
        canDelete: true,
        lat: 53.798823,
        lng:-1.5426760000000286,
        name: "CITY Varieties Music Hall",
        url: "https://plus.google.com/103655993956272197223/about?hl=en-GB",
        website: "http://www.cityvarieties.co.uk/",
        telNo: "0845 644 1881",
        street: "Swan Street,",
        town: "Leeds",
        area: "West Yorkshire",
        postCode: "LS1 6LW"
      }
    ],
    
    // Allows the user to delete a "custom" place they've previously 
    // ... added
    onDelete: function(mapsed, placeToDelete) {
			mapsed.showMsg(
        "YOUR DELETE CODE HERE",
        "<strong>" + placeToDelete.name + "</strong> has been removed."
      );
      
      // here would be code your application to do the actual delete
      
      // return true to confirm it was deleted OK and remove marker from the map
      // return false if the delete failed
      return true;
    },
		
    // Flag that we want the user to confirm the delete before we actually do it 
    confirmDelete: true		
  });
								

Enabling deletes is simply a matter of implementing the onDelete callback and the Delete button will appear when appropriate.

You can also ask the user to confirm the delete before they actually do it.


Searching for Places

All this viewing and editing custom places is nice, but a bit limiting. “I want to hook-up into Google's places API!”

show/hide code illustration

$("#search-for-places").mapsed({
  // Adds a predictive search box
  searchOptions: {
    enabled: true,
    initSearch: "Football in Leeds",
    placeholder: "Search ..."
  },
  
  // allow user to select somewhere
  onSelect: function(mapsed, details) {
    var msg = 
      "name: " + details.name +
      "street: " + details.street + ", " + 
      details.area + ", " + 
      details.town + ", " + details.postCode + 
      "telNo: " + details.telNo + 
      "website: " + details.website + 
      "more: " + details.url
    ;
		mapsed.showMsg("You selected ...", msg);
    // indicate tip should be closed
    return true;
  },
  
  // shows additional instructions to the user	
  getHelpWindow: function(mapsed) {
    var html = 
      "<div class='mapsed-help'>" +
        "<h3>Find a venue</h3>" +
        "<ol>" +
          "<li>Simply use the <strong>search</strong> box to find a venue in your area.</li>" +
          "<li>On the pop-up, click <strong>Select</strong> to pick a pitch.</li>" + 
        "</ol>" +
        "<h3>New venues</h3>" +
        "<ol>" +
          "<li>Your venue isn't displayed?  Simply click on the map where your pitch is.</li>" +
          "<li>Fill in the details in the dialog.</li>" + 
          "<li>You can drag the marker around to pinpoint the right location.</li>" + 
          "<li>Once you're happy, click the <strong>OK</strong> button</li>" + 
        "</ol>" +
      "</div>"
    ;
    return html;
  }
  
});
								

Searching is enabled through the searchOptions object (you simply flip a flag to enable it). The More button returns the next 20 hits.

Also notice that little [?] in the top-right corner of the map? This brings up a window telling your users what to do, and it's configurable of course, and you can have it show straight away.

And finally a GEO location icon (⊗) has been added to move the map location to that of the user's device, added simply by setting the allowGeo setting to true.


Database Integration

Loading places on start-up is great for just placing a few office locations on map. But if you have thousands of markers you'll need be able to hook into your back-end database.

This is where the onMapMoved hook comes into play.

show/hide code illustration

$("#map-moved").mapsed({

  onMapMoved: async function (north, south, east, west) {
    var hits = [];
    console.log("onMapMoved:", north, south, east, west);
    
    if (!_sporadicPlaces) {
      // emulate caching the result, or only hitting an in-memory array of results
      var resp = await fetch("/data/sporadic-places.json");
      _sporadicPlaces = await resp.json();
    }
    
    // Mimc back-end search for places within the boundary
    for (var i = 0; i < _sporadicPlaces.length; i++) {
      var place = _sporadicPlaces[i];
      
      var withinLat = (place.lat >= south && place.lat <= north);
      var withinLng = (place.lng >= west && place.lng <= east);
      
      if (withinLat && withinLng) {
        hits.push(place);
      }
    }
    
    console.log("Found", hits);
    return hits;
  },

});
									

In the example above there's no markers shown as the map isn't zoomed to a point where there are any to display. Keep zooming out and all will be revealed.

For bonus points, open DevTools, and you'll see feedback as it happens 😊.


Bringing it all together ...

One last feature is opening a map and taking over the full window, plus an illustration of adding in more controls (map style picker).

You'll notice a little [X] at the top-right corner to close it when you've finished.

Go full!

... added advantage of full window mode is you don't even need a DIV as a placeholder for the map!

see 06-full-example.js

Dependencies

Codebase

Mapsed was build to fulfil a need. The code is up on Github. I wouldn't look ... the code's horrible, but the plug-in does the job.

Unlike the theme I've used to tell you about mapsed which is very nice and clearly build with love.

License

Mapsed is released under a “Do what you like with it” license.