Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
# Helper function to get rid of repeating bindTo calls
google.maps.MVCObject::bindProperties: (object, options) ->
for key, value of options
this.bindTo key, object, value
# Add listener for few events at a time.
# For example marker.addListener 'dragged', 'distance_changed', updateForm
google.maps.MVCObject::addListener: (events..., __func) ->
for event in events
google.maps.event.addListener this, event, (listener) =>
# RadiusWidget is a circle and sizer marker
class RadiusWidget extends google.maps.MVCObject
constructor: ->
circle: new google.maps.Circle { strokeWeight: 2 }
this.set 'distance', 50
this.bindTo 'bounds', circle
circle.bindProperties this, {
center: 'center'
map: 'map'
radius: 'radius'
# magic funciton called on this.set 'distance', N
distance_changed: ->
this.set 'radius', this.get('distance') * 1000
# Adds sizer marker. When the sizer is dragged, changes circle radius
addSizer_: ->
sizer: new google.maps.Marker {
draggable: true
title: 'Drag me!'
icon: 'images/resize.png'
sizer.bindProperties this, {
map: 'map'
position: 'sizer_position'
google.maps.event.addListener sizer, 'drag', (event) => this.setDistance()
# Calculates distance between the sizer and center of the cirle and updates circle radius
setDistance: ->
pos: this.get 'sizer_position'
center: this.get 'center'
distance: this.distanceBetweenPoints_ center, pos
this.set 'distance', distance
# Moves sizer marker when the cirle is moved
center_changed: ->
bounds: this.get 'bounds'
if bounds
lng: bounds.getNorthEast().lng()
position: new google.maps.LatLng this.get('center').lat(), lng
this.set 'sizer_position', position
# Calculates distance between two given points
distanceBetweenPoints_: (p1, p2) ->
return 0 unless p1 and p2
R: 6371
dLat: ( - * Math.PI / 180
dLon: (p2.lng() - p1.lng()) * Math.PI / 180
a: Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos( * Math.PI / 180) * Math.cos( * Math.PI / 180) *
Math.sin(dLon / 2) * Math.sin(dLon / 2)
c: 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
d: R * c
# DistanceWidget is a marker with attached resizable circle.
# Use 'position', 'distance' and 'bounds' properties to get information about center, radius and bounds of the cirle.
class DistanceWidget extends google.maps.MVCObject
constructor: (map) ->
this.set 'map', map
this.set 'position', map.getCenter()
marker: new google.maps.Marker {draggable: true,title: 'Move me'}
marker.bindProperties this, {
map: 'map'
position: 'position'
radiusWidget: new RadiusWidget()
radiusWidget.bindProperties this, {
map: 'map'
center: 'position'
this.bindProperties radiusWidget, {
distance: 'distance',
bounds: 'bounds'
# Display changed center and radius of the circle
displayInfo: ->
info: document.getElementById('info')
info.innerHTML: 'Position: ' + this.get('position') + ', distance: ' + this.get('distance')
# Create map, add distance widget to the map
init: ->
mapDiv: document.getElementById('map-canvas')
latlang: new google.maps.LatLng(37.790234970864, -122.39031314844)
map_options: {
center: latlang,
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
mapTypeControl: false
map: new google.maps.Map mapDiv, map_options
distanceWidget: new DistanceWidget map
distanceWidget.addListener 'distance_changed', 'position_changed', displayInfo
google.maps.event.addDomListener window, 'load', init()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.